我使用boost.Asio使用UDP多播创建了一个应用程序 . 我认为这个问题并不是特定于boost.Asio而是一般的套接字编程,因为boost.Asio的网络设施大多是套接字函数的包装器 .
我基于组播示例(http://www.boost.org/doc/libs/1_44_0/doc/html/boost_asio/example/multicast/receiver.cpp和〜/ sender.cpp)构建了应用程序,并将其部署在运行在Windows,Linux和带有OSX Leopard的Mac上的几台计算机上 . 我很高兴所有平台上的多播都是开箱即用的,并且代码来自这些示例 .
我遇到问题的地方,就是当我断开网线时 . 当然,断开电缆总会引起问题;)但是有一些微妙的差异让我发疯 .
我的测试设置总是如下:一台机器运行发送器和接收器,以查看同一台机器是否接收到自己的多播,另一台机器只运行接收器 . 我在运行发送器和接收器的机器上拉网线 .
观察到的行为:
-
显然,接收器运行的机器不再接收任何消息 . 这是预期的;)
-
当拔出网络电缆的机器运行窗口时,发送器继续发送并且同一台机器上的接收器继续接收 . 没有检测到错误 . 看来windows有一个内在的回退环回?
-
当拔出网络电缆的机器运行Mac OSX时,发送器继续发送,不显示任何错误消息,但同一台机器上的接收器不再接收 . 在你问之前,我检查了不设置禁用环回选项 .
-
当拔出网络电缆的机器运行Linux时,发送器失败并出现boost :: error“网络无法访问” . 显然,由于发送方无法发送数据,接收方不再接收任何内容 .
对于Linux,我可以通过捕获“无法访问”错误(或写入错误的字节数)并在我的代码中设置一个标志来伪造Windows的行为,随后将所有数据发送到127.0.0.1而不是多播地址 . 我会定期检查多播 endpoints 上的send_to是否仍会产生错误,以检测网络重新连接并返回多播 . 这就像一个魅力,因为接收器是bind()到inaddr_any,因此也在127.0.0.1上监听 .
对于Mac OSX,我无法注意到网络何时无法访问以保持本地计算机上接收器的服务 .
我发现在Mac OSX上,当网络电缆重新插入并且DHCP尚未获得新的IP地址时,我会立即收到“网络无法访问”错误 .
所以基本上:我如何在MacOSX上实现,本地客户端仍然可以从本地发送者接收?通过检测网络丢失,就像我在Linux上做的那样,或者通过欺骗它来表现得像Windows一样 .
我们非常感谢任何对网络编程有深入了解的人的建议 .
2 回答
当我遇到这个问题时,我的解决方案是安排在网络配置发生变化时从操作系统获取通知 . 当我的程序收到该通知时,它将等待几秒钟(希望确保网络配置已完成更改),然后拆除并重建其所有套接字 . 这很痛苦,但似乎运作得很好 .
当然,当网络配置发生变化时,没有与操作系统无关的方式(我知道)从操作系统获得通知,因此我必须在每个操作系统下以不同方式实现它 .
对于MacOS / X,我产生了一个单独的watch-the-network-config线程,如下所示:
还有这个设置/支持代码,从上面的函数调用:
在Linux下(使用套接字(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE)))和Windows(使用NotifyAddrChange())获取网络配置更改通知的等效(也是相当模糊)机制,如果它们是,我可以发布很有帮助,但如果您只对MacOS / X解决方案感兴趣,我不想太多垃圾邮件 .
我认为在Windows中发生的事情是,即使断开电缆连接,Windows仍然保持以太网接口打开,因为您连接了一些套接字,并且您要发送的multicast_address保持有效 . Windows也可能会更改发送方/接收方正在使用的接口,因此更改在套接字级别是透明的 .
我认为在OS X中发生的事情是,当您断开电缆时,发送器会多播到环回接口,但接收器仍然连接到断开的以太网接口 . OS X也可能正在配置发送方发送给的自我分配的IP,但接收方仍在侦听旧的DHCP IP .
在Linux中,当您断开电缆连接时,以太网接口会失去它's IPv4 address, removes routes to 239.255.0.1, the loopback interface isn' t配置为发送任何内容在127 ... *之外,所以你得到一个错误 .
也许解决方案是定期重新加入OS X接收器上的组? (也许你还需要定期重建发送者的 endpoints . )
另一件事是在OS X上使用自我分配的IP,因此在连接或断开电缆时,您具有相同的IP和路由 .