我对网络编程很陌生,但是我正在开发一个个人项目,需要在局域网上的两台计算机之间进行接口。
对于我的所有网络需求,我正在使用boost。
由于在LAN上运行我的软件的计算机不知道彼此的IP地址,程序会立即发送UDP广播到255.255.255.255。另一台计算机侦听端口25566.如果计算机收到广播,它将回复另一个广播,以确保另一台以适当的方式通过TCP连接进行连接。
我有一台笔记本电脑和一台桌面电脑,都运行Linux。如果我在同一台机器上测试代码(同一件事的两个实例),一切都可以正常运行。但是,当我在笔记本电脑上运行一个实例而在桌面上运行另一个实例时会出现问题。发生了两种情况:
第一个 - 我在桌面计算机上运行该程序的一个实例。它发送“Hello”消息以检查另一个实例是否在LAN上的其他任何地方运行。由于没有其他实例在运行,因此它不会收到任何响应。几秒钟后,在桌面实例自行设置之后,我在笔记本电脑上启动了该程序的实例。笔记本电脑也播放“Hello”消息。但是,这就是问题所在。当笔记本电脑发送“Hello”消息时,桌面程序(已经运行)实际接收它的可能性只有10%。我在桌面计算机上使用Wireshark监控网络,而Wireshark再次仅在10%的时间内从笔记本电脑中接收广播。但是,如果我在发送“Hello”广播的笔记本电脑上运行Wireshark,Wireshark每次都会选择它。
第二个 - 这与第一个类似,只是笔记本电脑先运行程序。然后我几秒钟后启动桌面实例。但是,当桌面广播“Hello”时,笔记本电脑大约95%的时间接收广播(与角色转换时的10%相比)。然后笔记本电脑以“配置”广播进行响应。然后桌面几乎100%的时间接收“配置”广播。我再次确认了Wireshark的95%接收率。
我确信我的程序忽略这些数据包没有问题。但是,在广播数据包被忽略或过滤的网络中发生了某些事情。我觉得特别奇怪的是桌面程序如何仅在方案1中10%的时间收到“Hello”消息,但在方案2中100%的时间收到“配置”消息。如果发生了一些阻止数据包的奇怪事件从达到桌面,这两个百分比大致相等?
以下是我为设置必要套接字而运行的一些代码:
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
基本上我的问题是,为什么我的一些广播没有通过?
由于
编辑:
另外,我忘了提到每台计算机每次都收到它的OWN广播。所以我认为这是网络问题,而不是我的代码。
答案 0 :(得分:4)
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)
这更适合您的应用程序。您必须根据网络配置选择一个好的组端点,因此它涉及的内容稍微多一些。
然而,您将获得所有现代路由器硬件/软件的支持,以确保交付给感兴趣的各方(仅限)。