Ich versuche, ein UDP-Paket mit Boost Asio zu erhalten. Mein Code basiert auf this blocking UDP client example from the asio documentation.Warum empfängt dieses Programm nicht die erwarteten UDP-Pakete?
Ich versuche, ein BOOTP-ähnliches UDP-Paket von einem C6655 TI DSP zu empfangen, die in 3-Sekunden-Intervallen übertragen werden. Ich habe Wireshark, der die gleiche Schnittstelle beobachtet, die mein Programm überwacht, und es kann die eingehenden Pakete sehen (siehe unten für die genauen Paketdaten, die von Wireshark exportiert wurden). Die Pakete sind nicht wirklich kommen aus dem DSP, habe ich eins mit tcpdump
gefangen und ich simuliere es von einem Raspberry Pi mit packeth.
Allerdings empfängt mein Programm die Pakete nicht. Es hat einen Timeout von 4 Sekunden (da der DSP alle 3 Sekunden sendet). Wenn es das Zeitlimit erreicht, gibt es eine entsprechende Nachricht aus, andernfalls soll es die Anzahl der empfangenen Bytes drucken. Der vollständige (kompilierbare) Quellcode des Programms folgt (etwa 100 Zeilen).
Der Befehl wird mit den Parametern 192.168.5.122 67 4000
aufgerufen, was bedeutet, dass 192.168.5.122:67 mit einer Zeitüberschreitung von 4.000 Millisekunden überwacht wird.
Edit: Zusätzlich zu dem Code unten, habe ich auch versucht, dies als mein Endpunkt: udp::endpoint listen_endpoint(boost::asio::ip::address_v4::any(), atoi(argv[2]));
sowie die IP-Adresse 0.0.0.0
wie von einem Suchergebnis irgendwo vorgeschlagen.
Ich habe auch die folgenden ohne Erfolg:
boost::asio::socket_base::broadcast option(true);
socket_.set_option(option);
ich ein Programm, das dieses Paket in der Lage, mit Berkeley Sockeln zu erhalten, geschrieben. Es macht nichts besonderes, was ich sehen kann, außer Bindung an INADDR_ANY. Hier
ist das vollständige Programm:
//
// blocking_udp_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <iostream>
using boost::asio::deadline_timer;
using boost::asio::ip::udp;
class listener
{
public:
listener(const udp::endpoint& listen_endpoint)
: socket_(io_service_, listen_endpoint)
, deadline_(io_service_)
{
deadline_.expires_at(boost::posix_time::pos_infin);
check_deadline();
}
std::size_t receive(const boost::asio::mutable_buffer& buffer, boost::posix_time::time_duration timeout, boost::system::error_code& ec)
{
deadline_.expires_from_now(timeout);
ec = boost::asio::error::would_block;
std::size_t length = 0;
socket_.async_receive(boost::asio::buffer(buffer), boost::bind(&listener::handle_receive, _1, _2, &ec, &length));
// TODO: The following do/while is hinky. Does run_one() need to happen before the comparison?
do io_service_.run_one();
while (ec == boost::asio::error::would_block);
return length;
}
private:
void check_deadline()
{
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
{
// cancel() won't work on XP. Something about using close() instead... Look it up. I'm doing this on Win10.
socket_.cancel();
deadline_.expires_at(boost::posix_time::pos_infin);
}
deadline_.async_wait(boost::bind(&listener::check_deadline, this));
}
static void handle_receive(const boost::system::error_code& ec, std::size_t length, boost::system::error_code* out_ec, std::size_t* out_length)
{
*out_ec = ec;
*out_length = length;
}
private:
boost::asio::io_service io_service_;
udp::socket socket_;
deadline_timer deadline_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 4)
{
std::cerr << "Usage: blocking_udp_timeout <listen_addr> <listen_port> <timeout_ms>\n";
return 1;
}
udp::endpoint listen_endpoint(boost::asio::ip::address::from_string("0.0.0.0"), atoi(argv[2]));
std::cout << "Endpoint: " << listen_endpoint << std::endl;
auto timeout = atoi(argv[3]);
std::cout << "Timeout : " << timeout << std::endl;
listener c(listen_endpoint);
for (;;)
{
char data[1024];
boost::system::error_code ec;
auto n = c.receive(boost::asio::buffer(data), boost::posix_time::milliseconds{timeout}, ec);
if (ec)
{
std::cout << "Receive error: " << ec.message() << "\n";
}
else
{
std::cout << "Received " << n << " bytes." << std::endl;
}
}
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Hier ist das Paket, das ich erhalten werde versuchen. Dazu gehört auch die Ethernet-Frame:
0000 ff ff ff ff ff ff c4 ed ba aa 28 35 08 00 45 00 ..........(5..E.
0010 01 48 00 01 00 00 10 11 a9 a5 00 00 00 00 00 00 .H..............
0020 00 00 00 44 00 43 01 34 00 00 01 01 06 00 12 34 ...D.C.4.......4
0030 56 78 00 01 00 00 00 00 00 00 00 00 00 00 00 00 Vx..............
0040 00 00 00 00 00 00 c4 ed ba aa 28 35 00 00 00 00 ..........(5....
0050 00 00 00 00 00 00 74 69 2d 62 6f 6f 74 2d 74 61 ......ti-boot-ta
0060 62 6c 65 2d 73 76 72 00 00 00 00 00 00 00 00 00 ble-svr.........
0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0090 00 00 00 00 00 00 74 69 2d 62 6f 6f 74 2d 74 61 ......ti-boot-ta
00a0 62 6c 65 2d 30 30 30 37 00 00 00 00 00 00 00 00 ble-0007........
00b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0150 00 00 00 00 00 00 ......
Ich habe eine Socket-Implementierung Berkeley, die dieses Paket empfangen kann (I Fehlerbehandlung und andere misc entfernt Code.):
{
struct sockaddr_in servaddr;
socklen_t len;
char mesg[RECV_BUFFER_LENGTH];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(67);
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
n = recvfrom(sockfd, mesg, RECV_BUFFER_LENGTH, 0, NULL, &len);
}
BOOTP ist normalerweise ein Broadcast, der spezielle Flags benötigt, um –
@BenVoigt zu empfangen Kannst du erklären, wie man das mit 'boost :: asio' macht? – Steve
Ich habe versucht, auf Port '0' zu hören (was seltsam scheint), wie es von einigen anderen Suchergebnissen vorgeschlagen wurde, aber ohne Erfolg. – Steve