2017-12-15 8 views
0

Ich habe ein Geräteerkennungsprogramm geschrieben, das im Client- oder Servermodus ausgeführt werden kann. Im Client-Modus sendet es ein UDP-Broadcast-Paket an 255.255.255.255 an Port 30000 und wartet dann auf Antworten auf Port 30001. Im Server-Modus wartet es auf UDP-Broadcast auf Port 30000 und sendet ein UDP-Broadcast-Paket an 255.255.255.255 auf Port 30001 In Beantwortung.Wie empfange ich eine UDP-Sendung gesendet an 255.255.255.255 mit Boost Asio?

Wenn ich dieses Programm auf 2 Geräten mit den IP-Adressen 192.168.10.61 und 192.168.10.62 starte, funktioniert alles einwandfrei. Der Sinn dieses Programms besteht darin, dass Geräte mit unbekannten IP-Adressen sich gegenseitig erkennen können, solange sie mit demselben physikalischen Netzwerk verbunden sind. Um das zu testen, änderte ich die IP-Adresse des ersten Geräts in etwas zufälliges wie 12.34.56.42/255.255.240. Und jetzt hört es auf zu arbeiten.

Mit tcpdump auf der 192.168.10.62 Maschine kann ich sehen, dass das UDP-Paket von der 12.134.56.42 Maschine empfangen wurde:

# tcpdump -i eth0 port 30000 -c 1 -v 
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 
17:38:02.552427 IP (tos 0x0, ttl 64, id 18835, offset 0, flags [DF], proto UDP (17), length 49) 
12.34.56.42.56815 > 255.255.255.255.30000: UDP, length 21 
1 packet captured 
6 packets received by filter 
0 packets dropped by kernel 

aber meine Entdeckung Programm nicht mehr erhält es. Dies ist der Code, den ich die UDP-Broadcast-Pakete empfangen bin mit:

int WaitForPacket(uint16_t portNum, vector<char>& udpBuf, udp::endpoint& remoteEndpoint, const chrono::milliseconds timeout) 
{ 
    io_service ioService; 

    udp::socket socket(ioService, udp::endpoint(boost::asio::ip::address_v4::any(), portNum)); 
    socket.set_option(socket_base::broadcast(true)); 

    boost::system::error_code error; 
    int numBytes = receive_from(socket, buffer(udpBuf), remoteEndpoint, error, timeout); 

    if (error && error != error::message_size && error != error::timed_out) 
    { 
     printf("Got error: %s\n", error.message().c_str()); 
     return -1; 
    } 

    return numBytes; 
} 

/* 
* The boost asio library does not provide a blocking read with timeout function so we have to roll our own. 
*/ 
int receive_from(
    boost::asio::ip::udp::socket&   socket, 
    const boost::asio::mutable_buffers_1& buf, 
    boost::asio::ip::udp::endpoint&  remoteEndpoint, 
    boost::system::error_code&   error, 
    chrono::milliseconds     timeout) 
{ 
    volatile bool ioDone = false; 
    int numBytesReceived = 0; 
    boost::asio::io_service& ioService = socket.get_io_service();  

    socket.async_receive_from(buf, remoteEndpoint, 
           [&error, &ioDone, &numBytesReceived](const boost::system::error_code& errorAsync, size_t bytesReceived) 
           { 
            ioDone = true; 
            error = errorAsync; 
            numBytesReceived = bytesReceived; 
           }); 

    this_thread::sleep_for(chrono::milliseconds(100)); 
    ioService.reset(); 
    ioService.poll_one(); 

    auto endTime = chrono::system_clock::now() + timeout; 

    while (!ioDone) 
    { 
     ioService.reset(); 
     this_thread::sleep_for(chrono::milliseconds(100)); 
     auto now = chrono::system_clock::now(); 
     if (now > endTime) 
     { 
      socket.cancel(); 
      error = error::timed_out; 
      return 0; 
     } 
     ioService.poll_one(); 
    } 
    ioService.reset(); 

    return numBytesReceived; 
} 

ich ähnliche Fragen auf Stack-Überlauf überprüft und festgestellt, einige, die die Aufnahmebuchse gesagt hat INADDR_ANY um gebunden sein Broadcast-Pakete zu empfangen. Ich habe ursprünglich den Sockel wie diese udp::socket socket(ioService, udp::endpoint(udp::v4(), portNum)); erstellt, aber jetzt geändert, um stattdessen ip::address_v4::any() zu verwenden. Das machte keinen Unterschied.

Kann mir jemand sagen, was ich ändern muss, um das UDP-Broadcast-Paket wie erwartet zu empfangen?

Ich führe dies auf iMX6-Geräten mit Linux und bin Compiling mit Boost 1.58.

+0

Sie empfangen keine Datagramme, da Sie den Computer automatisch von der lokalen Netzwerkadresse ausschließen, indem Sie die erste Adresse in 12.34.56.42/255.255.240 ändern. Und da die Übertragung nur in LAN-Umgebungen funktioniert, erhalten Sie die Nachricht nicht vollständig. Ihr Computer ist möglicherweise mit dem gleichen Netzwerk mit einer gefälschten IP-Adresse verbunden, und diese gefälschte IP-Adresse ist der Grund dafür, dass die Broadcastnachricht nicht vollständig empfangen wird. – Ivan86

+0

Möglicherweise müssen Sie ein privates Netzwerk für die erkennbaren Geräte einrichten, mit denen alle zuvor verbunden waren, aber das ist nicht wirklich eine Entdeckung. Sie können jedoch Ihr WLAN offen lassen und dies auf Besucher anwenden, die eine Verbindung zu Ihrem Router herstellen. – Ivan86

+0

Eine Möglichkeit, mit beliebigen Adressen umzugehen, wäre, die IP-Adresse des Absenders in den Broadcast-Paketen manuell auf 0.0.0.0 zu setzen (das ist im Grunde auch, wie DHCP funktioniert). Frag mich nicht, wie ich das mit Boost erreichen kann. Vielleicht https://stackoverflow.com/questions/28196466/in-boost-asio-how-can-i-set-the-source-ip-address-to-impersonate-another-server ist hilfreich, soweit ich sehen kann . –

Antwort

1

Ich entdeckte schließlich, warum mein Code die broadcast Pakete nie sah, obwohl tcpdump bewies, dass sie empfangen wurden. Nach der Feststellung dieser Frage Stackoverflow:

Disable reverse path filtering from Linux kernel space

scheint es, dass ich Reverse Path Filtering auf beiden Hosts wie diese zu deaktivieren nur benötigt, um meinen Code funktionierte perfekt ohne Modifikationen

echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter 
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter 

und dann. Hoffentlich wird dies anderen Leuten helfen, sich zu wundern, warum sie keine UDP-Übertragungen an die Netzwerk-Broadcast-Adresse (255.255.255.255) erhalten können.

+0

Sie sind ein Lebensretter! Vielen Dank. – Isaac

+1

Ich möchte hinzufügen, dass ich schließlich auf IPv6 anstelle von IPv4 aufgrund von Problemen unter Windows 7 wechselte, wo ich keine Möglichkeit zum Hinzufügen einer Verbindung lokalen IPv4-Adresse zu einer Schnittstelle finden konnte, die mit DHCP konfiguriert wurde. IPv6 funktioniert viel besser für die Geräteerkennung, wenn Sie automatisch eine lokale Adresse für die Verbindung konfigurieren, sodass Sie einfach eine UDP-Übertragung an FF02 :: 1 senden können. Kein Problem mit der Deaktivierung der umgekehrten Pfadfilterung und keine Probleme beim Einrichten einer lokalen Linkadresse unter Windows 7. –

+0

Oh, ich verstehe. Danke für die Information. – Isaac