UDP广播淹没的NodeJs Server无法发送响应

时间:2018-10-15 09:02:49

标签: javascript c++ node.js arduino udp

我正在使用ESP8266 / NodeMcu模块(类似于Arduino,仅具有联网功能)和在本地网络上运行的NodeJs服务器来构建系统。

要发现服务器的IP地址,我试图在NodeMcu模块上使用UDP广播。这个想法是在本地广播IP(例如192.168.1.255)上发送一条消息。然后,服务器接收到该消息并发送响应,确认它是服务器。这样,NodeMcu知道服务器的直接地址以进行进一步的通信。

问题是,每当服务器从NodeMcu收到第一条消息时,服务器就会完全用同一条消息淹没自己,而NodeMcu实际上仅每秒发送一次消息。

在NodeMcu端看起来像这样:

[UDP] Sending UDP Broadcast on IP: 192.168.43.255, Port: 8080, Message: ESP8266 UDP Server Discovery Broadcast

服务器每秒输出多次这样的信息:

[10:33:07] 127.0.0.1:8080 @ service discovery : ESP8266 UDP Server Discovery Broadcast
[10:33:07] 127.0.0.1:8080 @ service discovery : ESP8266 UDP Server Discovery Broadcast
[10:33:07] 127.0.0.1:8080 @ service discovery : ESP8266 UDP Server Discovery Broadcast

接收很多消息是没有意义的,尤其是因为它显然来自127.0.0.1,而不是来自NodeMcu的IP。它也不会发出任何响应。

我尝试使用UDP Monitor app,一个名为Packet Sender的应用程序和Linux Terminal在手机上接收广播。一切正常,发送手动响应会触发NodeMcu上的确认。

所以我认为服务器或我使用的网络必须存在某种错误。该服务器在我计算机上的Linux上运行,而我通过手机上的热点托管网络(我的真实WiFi网络阻止了UDP广播)。 Linux防火墙已关闭。

我无论如何都不是JavaScript或NodeJ的专家,并且服务器是由与我一起工作的人编写的,但是他也没有任何线索。无论如何,这是服务器上的重要部分:

client.on('listening', function () {
  var address = client.address();
  debugMessage(
    format('Service discovery running on port %s', config.port)
  );
  client.setBroadcast(true);
});

client.on('message', function (message, rinfo) {
  debugMessage(
    format('%s:%s @ service discovery : %s', rinfo.address, rinfo.port, message)
  );
  client.send(message, 0, message.length, rinfo.port, rinfo.ip);
});

client.bind(config.port);

NodeMcu上的代码如下:

#include <ESP8266WiFi.h>        // WiFi library
#include <WiFiUdp.h>            // UPD functionality

// UDP variables
WiFiUDP udp;
unsigned int localUdpPort = 8080;
char incomingPacket[255];
const char broadcastMessage[] = "ESP8266 UDP Server Discovery Broadcast";

// Server details - written to when the server is found
IPAddress serverIp = ~WiFi.subnetMask() | WiFi.gatewayIP(); // Use Broadcast Address as default in case the UDP service discovery isn't working as intended
unsigned int serverPort = localUdpPort; // Use local port as default in case the UDP service discovery ins't working as intended

void setupWiFi()
{
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  #if LOGGING
  Serial.println("Connecting to network: " + (String) WIFI_SSID);
  #endif

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(100);
  }

  #if LOGGING
  Serial.print("Connected to network, Local IP Address: ");
  Serial.println(WiFi.localIP());
  #endif

  udp.begin(localUdpPort); // begin listening on UDP port
  #if LOGGING
  Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
  #endif LOGGING
}

// Discover the server via a UDP broadcast, and store it's IP and Port in the local network in field variables for later use
// IMPORTANT - For the server to work, the Linux Firewall has to be disabled!!!
void discoverServer()
{
  changeColor(PURPLE, false); // change the color of the RGB status LED to signal that the program is searching for the server

  bool serverFound = false; // stop when the server is found

  IPAddress broadcastIp = ~WiFi.subnetMask() | WiFi.gatewayIP(); // Get the Broadcast IP of the local network (e.g. 192.168.0.255)

  while (!serverFound)
  {
    // Send UDP Broadcast
    udp.beginPacket(broadcastIp, localUdpPort);
    udp.write(broadcastMessage);
    udp.endPacket();

    #if LOGGING
    Serial.printf("[UDP] Sending UDP Broadcast on IP: %s, Port: %d, Message: %s\n", broadcastIp.toString().c_str(), localUdpPort, broadcastMessage);
    #endif

    delay(1000); // Pause a few milliseconds to avoid flooding the network

    // Receive UDP packets
    int packetSize = udp.parsePacket();
    if (packetSize > 0)
    {
      // Read incoming UDP Packet
      int len = udp.read(incomingPacket, 255);
      if (len > 0)
      {
        incomingPacket[len] = 0;
      }

      #if LOGGING
      Serial.printf("[UDP] Received %d bytes from %s, port %d\n", packetSize, udp.remoteIP().toString().c_str(), udp.remotePort());
      Serial.printf("[UDP] Packet contents: %s\n", incomingPacket);
      #endif

      // Check if the received message is from the server we are searching for
      if (strcmp(incomingPacket, broadcastMessage) == 0)
      {
        serverIp = udp.remoteIP();
        serverPort = udp.remotePort();

        #if LOGGING
        Serial.printf("[UDP] Found Server on IP: %s, Port: %d\n", serverIp.toString().c_str(), serverPort);
        #endif

        serverFound = true;
        changeColor(YELLOW, false); // Change status color of RGB LED back to yellow
      }
    }
  }
}

我真的很想知道服务器,网络或NodeMcu是否出了问题。尤其是因为我尝试的所有其他方法均能完美工作,而并非是从NodeMcu发送时。非常感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

原来,服务器代码中有错误。 代替

client.send(message, 0, message.length, rinfo.port, rinfo.ip);

应该已经

client.send(message, 0, message.length, rinfo.port, rinfo.address);

服务器不知道rinfo.ip,因此它一遍又一遍地向同一封邮件发送垃圾邮件。