NodeJs 服务器充斥着 UDP 广播,不发送响应
NodeJs Server flooded with UDP Broadcasts, doesn't send response
我正在本地网络上使用 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, an application called Packet Sender 和 Linux 终端在我的 phone 上接收广播。一切正常,发送手动响应触发了 NodeMcu 上的确认。
所以我认为服务器或我正在使用的网络一定存在某种错误。服务器在我计算机上的 Linux 上 运行,而我通过 phone 上的热点托管网络(我的真实 WiFi 网络阻止了 UDP 广播)。 Linux 防火墙已关闭。
无论如何,我都不是 JavaScript 或 NodeJs 方面的专家,并且服务器是由与我一起工作的人编写的,但他也不知道。无论如何,这是服务器上的重要部分:
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 发送它时就不行了。非常感谢任何帮助!
原来是服务器代码出错了。
而不是
client.send(message, 0, message.length, rinfo.port, rinfo.ip);
应该是
client.send(message, 0, message.length, rinfo.port, rinfo.address);
服务器不知道 rinfo.ip
,所以它一遍又一遍地向自己发送相同的垃圾邮件。
我正在本地网络上使用 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, an application called Packet Sender 和 Linux 终端在我的 phone 上接收广播。一切正常,发送手动响应触发了 NodeMcu 上的确认。
所以我认为服务器或我正在使用的网络一定存在某种错误。服务器在我计算机上的 Linux 上 运行,而我通过 phone 上的热点托管网络(我的真实 WiFi 网络阻止了 UDP 广播)。 Linux 防火墙已关闭。
无论如何,我都不是 JavaScript 或 NodeJs 方面的专家,并且服务器是由与我一起工作的人编写的,但他也不知道。无论如何,这是服务器上的重要部分:
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 发送它时就不行了。非常感谢任何帮助!
原来是服务器代码出错了。 而不是
client.send(message, 0, message.length, rinfo.port, rinfo.ip);
应该是
client.send(message, 0, message.length, rinfo.port, rinfo.address);
服务器不知道 rinfo.ip
,所以它一遍又一遍地向自己发送相同的垃圾邮件。