LAN 上的计算机不会始终使用 boost::asio C++接收到 255.255.255.255 的 UDP 广播

Computers on LAN do not consistently receive a UDP broadcast to 255.255.255.255 using boost::asio C++

本文关键字:C++ asio UDP 广播 计算机 LAN boost      更新时间:2023-10-16

我对网络编程很陌生,但我正在从事一个个人项目,该项目需要在局域网上的两台计算机之间进行接口。

对于我所有的网络需求,我正在使用boost。

由于在LAN上运行我的软件的计算机不知道彼此的IP地址,因此程序会立即向255.255.255.255发送UDP广播。另一台计算机侦听端口 25566。如果一台计算机收到广播,它会回复另一个广播,以确保另一台计算机以适当的方式通过 TCP 连接进行连接。

我有一台笔记本电脑和一台台式机,都运行Linux。如果我在同一台机器上测试代码(同一事物的两个实例),一切都可以完美运行。但是,当我在笔记本电脑上运行一个实例,在桌面上运行另一个实例时,会出现问题。发生两种情况:

第一个 - 我在台式计算机上运行该程序的一个实例。它发送"Hello"消息以检查另一个实例是否正在 LAN 上的任何其他位置运行。由于没有其他实例正在运行,因此它不会收到响应。几秒钟后,在桌面实例自行设置后,我在笔记本电脑上启动该程序的实例。笔记本电脑也会广播"你好"消息。然而,这就是问题开始的地方。当笔记本电脑是发送"Hello"消息的人时,桌面程序(已经在运行)实际收到它的可能性只有大约 10%。我在台式机器上使用Wireshark监控网络,同样,Wireshark仅在10%的时间内从笔记本电脑接收广播。但是,如果我在发送"Hello"广播的笔记本电脑上运行Wireshark,Wireshark每次都会接听它。

第二个 - 这与第一个类似,只是笔记本电脑首先运行程序。然后,我在几秒钟后启动桌面实例。但是,当桌面广播"Hello"时,笔记本电脑大约 95% 的时间会收到广播(相反,角色颠倒时为 10%)。然后,笔记本电脑以"配置"广播进行响应。然后,桌面几乎 100% 的时间接收"配置"广播。我再次与Wireshark确认了95%的接收率。

我确信我的程序忽略这些数据包没有问题。但是,网络中发生了一些事情,广播数据包被忽略或过滤。我觉得特别奇怪的是,桌面程序在场景 1 中只收到 10% 的时间接收"Hello"消息,而在场景 100% 的时间收到"配置"消息 2。如果发生了一些奇怪的事情,阻止数据包到达桌面,那么这两个百分比不是大致相等吗?

以下是我运行的一些代码来设置必要的套接字:

broadcast_socket = new udp::socket(*ioservice); //Set up the socket that broadcasts the message
listen_socket = new udp::socket(*ioservice); //Set up the socket on port 25565 that listens for a broadcast
//Set up the ioservice...
error_code e1, e2;
broadcast_socket->open(udp::v4(), e1); //Actually open the sockets
listen_socket->open(udp::v4(), e2);
//Do some error code checking...
listen_endpoint = udp::endpoint(ip::address_v4::any(), port); //Get endpoint for port 25566 (listen_endpoint becomes 0.0.0.0:25566 after this call)
listen_socket->set_option(udp::socket::reuse_address(true));
listen_socket->bind(listen_endpoint);
broadcast_socket->set_option(udp::socket::reuse_address(true));
broadcast_socket->set_option(socket_base::broadcast(true));
broadcast_endpoint = udp::endpoint(ip::address_v4::broadcast(), port); //Get the broadcast_endpoint (returns 255.255.255.255)

以下是我用来接收广播消息的代码:

error_code ec;
size_t available_bytes = listen_socket->available(ec); //See if data is available
size_t read_bytes = 0;
char buffer[1024];
if(available_bytes > 0 && !ec){
read_bytes = listen_socket->receive_from(boost::asio::buffer(buffer, (available_bytes < sizeof(buffer) ? available_bytes : sizeof(buffer))), listen_endpoint);
read_data.append(buffer, read_bytes); //Append to a string for later processing
}

最后,这是我发送数据的方式:

std::string payload = "Some payload stuff goes here";
broadcast_socket->send_to(boost::asio::buffer(payload, payload.size()), broadcast_endpoint); //Broadcasts to the broadcast_endpoint (255.255.255.255) which was determined earlier

所以基本上我的问题是,为什么我的一些广播没有通过?

谢谢

编辑:

另外,我忘了提到每台计算机每次都会收到自己的广播。所以我认为这是网络的问题,而不是我的代码。

UDP 不保证提供。这是协议属性的一部分。

你可以观察Wireshark的行为,这一事实证实了它与Boost几乎没有关系。

使用 255.255.255.255是一种钝器,它是有限的:

将 IP 地址的所有位设置为 1 或 255.255.255.255,形成有限的广播地址。向此地址发送 UDP 数据报会将消息传递到本地网段上的任何主机。由于路由器从不转发发送到此地址的消息,因此只有网段上的主机才会接收广播消息。

通过使用子网掩码,您可以更具针对性:

通过设置主机标识符的所有位,可以将广播定向到网络的特定部分。例如,要将广播发送到网络上由以 192.168.1 开头的 IP 地址标识的所有主机,请使用地址 192.168.1.255。

这增加了路由器知道将数据包发送到何处的机会(我不是网络工程师,所以我不确定实现细节)。

输入多播组

与广播传输(在某些局域网上使用)不同,组播客户端仅在先前选择这样做(通过加入特定的组播组地址)时才接收数据包流。组的成员身份是动态的,由接收方控制(反过来由本地客户端应用程序通知)。

(来源:http://www.erg.abdn.ac.uk/users/gorry/course/intro-pages/uni-b-mcast.html)

这更有可能适合您的应用程序。您必须根据网络配置选择一个好的组终结点,因此它稍微复杂一些。

但是,您将获得所有现代路由器硬件/软件的支持,以确保(仅)交付给感兴趣的各方。