UdpClient.BeginReceive()不会接收,除非它之前没有发送过
本文关键字:BeginReceive UdpClient | 更新日期: 2023-09-27 18:18:43
我正在调试一个奇怪的问题,发生在运行环境中的一台机器上。
我的应用程序(从)应该在任何时候从LAN中的另一个主机(主)接收UDP多播消息,但显然它只有在从之前发送消息时才这样做。
我期望的是:
- 从服务器请求数据
- 主机发送数据
- Slave接收和消耗
- 主端等待2-3分钟
- 主机发送新数据
- Slave接收并使用新数据
- 步骤4到6重复
我看到的是:
- Slave没有收到任何信息
但是如果我让slave连续请求新数据(轮询,即重复步骤1),我最终得到消息。
我在Wireshark中看到,从主机确实收到了来自主主机的消息。只是我的应用没有接收到。更令人惊讶的是,在同一网络上运行相同应用程序的另一个主从对运行良好,测试环境中的我的对也是如此。
从端应用异步使用UdpClient
。下面是如何初始化侦听器的:
private void ListenMain()
{
try
{
UdpClient udpClient = new UdpClient();
udpClient.Client.ExclusiveAddressUse = false;
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
IPv4InterfaceProperties p = adapter.GetIPProperties().GetIPv4Properties();
udpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)IPAddress.HostToNetworkOrder(p.Index));
udpClient.Client.Bind(endPoint);
udpClient.JoinMulticastGroup(12345);
ListenState listenState = new ListenState();
listenState.udpClient = udpClient;
listenStates.Add(listenState);
logger.Debug("Waiting for messages");
udpClient.BeginReceive(new AsyncCallback(OnPacketReceived), listenState);
}
catch (Exception e)
{
logger.Error(e, "ListenMain() encountered an error");
}
}
下面是接收到的数据包的处理程序:
private void OnPacketReceived(IAsyncResult result)
{
logger.Trace("OnPacketReceived");
IPEndPoint recvAddress = new IPEndPoint(IPAddress.Any, MULTICAST_PORT);
ListenState state = result.AsyncState as ListenState;
byte[] receive_byte_array;
try
{
logger.Trace("before EndReceive");
receive_byte_array = state.udpClient.EndReceive(result, ref recvAddress);
logger.Trace("after EndReceive, got {0} bytes", receive_byte_array.Length);
// packet handling goes here...
// do the loop
logger.Trace("waiting for another packet");
state.udpClient.BeginReceive(new AsyncCallback(OnPacketReceived), state);
}
catch (ObjectDisposedException)
{
logger.Info("Socket is now closed");
return;
}
catch (Exception e)
{
logger.Warn(e, "exception in handling incoming message");
}
}
当然,轮询新数据不是最优解决方案,并且会引入不必要的延迟。我想知道哪种现象使UdpClient丢失传入数据包,除非相同的UdpClient之前发送了一些东西。
我认为代码中存在错误:udpClient.JoinMulticastGroup();
将多播IP地址作为参数,而不是端口。当你修复这个的时候,它能工作吗?如果是,解释如下:
未加入组播组将导致典型的"未加入组播组";行为不稳定,其中包括最喜欢的"它工作了两到五分钟,然后突然停止";当我向另一个方向发送一些东西,然后突然停止时,它会起作用。并且"它在使用不同的组播地址时工作,然后停止,留下不可用的组播地址"。
你看到的行为是典型的IPv4多播或多或少智能路由器和交换机。它们都支持某些版本的IGMP窥探(有超时、错误和不兼容的版本),路由器、交换机和操作系统缓存网络路径和mac以及注册和未注册的多播ip,时间不确定。这使得无法以逻辑的方式对行为进行推理。
检查您是否在接收端/侦听端加入了预期的多播组。如果这看起来没问题,但您仍然有问题,请跟踪IGMP消息并查找任何不合理的内容,例如从未看到连接,或看到不稳定的叶子。
(注意IGMP消息是由操作系统在机器级别发送的,而不是由应用程序发送的。这意味着不是每个JoinMulticastGroup()都会生成IGMP连接消息。