我有一个发送多播数据包的应用程序。
我使用BlockingCollection来存储我要发送的消息,然后一个线程专门用于发送迭代此集合并在其中发送消息。我为每个本地IP都有一个套接字,因为我需要在每个IP上发送它。
它通常很好用,但是最近,我有几次我的线程挂在Socket.SendTo调用上,导致我的应用程序不再响应任何外部调用。我的BlockingCollection变得越来越大,永远不会被处理。
我找不到任何理由让这个阻止我的电话的Socket.SendTo电话。如果是TCP呼叫,我可以想象另一边没有人,但是在这里有UDP,我没有看到任何可能的问题。
我的代码基本上是:
Debug.WriteLine("Sending message on local endpoint " + socket.Key + ", to " + remoteEndpoint);
int sendTo = socket.Value.SendTo(buffer, remoteEndpoint);
Debug.WriteLine("Successfully sent a packet with "+sendTo+" bytes");
在我的日志中,我看到:
[...]
Sending message on local endpoint 10.10.23.56, to 224.0.0.253:5353
Successfully sent a packet with 778 bytes
Sending message on local endpoint 10.9.53.38, to 224.0.0.253:5353
Successfully sent a packet with 778 bytes
Sending message on local endpoint 127.0.0.1, to 224.0.0.253:5353
Successfully sent a packet with 778 bytes
Sending message on local endpoint 10.10.23.56, to 224.0.0.253:5353
Successfully sent a packet with 778 bytes
Sending message on local endpoint 10.9.53.38, to 224.0.0.253:5353
Successfully sent a packet with 778 bytes
Sending message on local endpoint 127.0.0.1, to 224.0.0.253:5353
Successfully sent a packet with 778 bytes
Sending message on local endpoint 10.10.23.56, to 224.0.0.253:5353
Successfully sent a packet with 778 bytes
Sending message on local endpoint 10.9.53.38, to 224.0.0.253:5353¨
我像这样创建我的套接字:
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255);
sendSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sendSocket.MulticastLoopback = true;
sendSocket.Bind(new IPEndPoint(localAddress, m_port));
sendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,new MulticastOption(m_multicastAddress, localAddress));
我看到here它已阻止,直到我的所有邮件都被发送,但出于什么原因我的邮件可能会被阻止?但是在这里,我的通话在这里被禁止了。
该怎么办?有没有时间处理Socket并尝试在我的数据包未发送时再创建它?
编辑:我试图用异步发送/接收做同样的事情,但更糟糕的是:我仍然在EndReceiveTo上被阻止,但另外,它阻止我杀死进程(访问被拒绝,我是管理员,有重启:/)修改 在xaxxon回答之后,我在发送消息之前把它放在一边,看看我是否有套接字我无法写入或出错:
List<Socket> socketWrite = socketToUse.Select(s => s.Value).ToList();
List<Socket> socketError = socketToUse.Select(s => s.Value).ToList();
Socket.Select(null, socketWrite, socketError, 1000);
Console.WriteLine("Writeable sockets: " + String.Join(", ", socketWrite.Select(s => s.LocalEndPoint.ToString())));
Console.WriteLine("Sockets in errors: " + String.Join(", ", socketError.Select(s => s.LocalEndPoint.ToString())));
But before I enter I get stuck on my `SendTo` call,
Writeable sockets: 10.10.23.56:5353, 10.9.53.38:5353, 127.0.0.1:5353
Sockets in errors:
Sending message on local endpoint 10.10.23.56, to 224.0.0.253:5353
Successfully sent a packet with 93 bytes
Sending message on local endpoint 10.9.53.38, to 224.0.0.253:5353
Successfully sent a packet with 93 bytes
Sending message on local endpoint 127.0.0.1, to 224.0.0.253:5353
Successfully sent a packet with 93 bytes
Writeable sockets: 10.10.23.56:5353, 10.9.53.38:5353, 127.0.0.1:5353
Sockets in errors:
Sending message on local endpoint 10.10.23.56, to 224.0.0.253:5353
Successfully sent a packet with 1162 bytes
Sending message on local endpoint 10.9.53.38, to 224.0.0.253:5353
__HERE I GET STUCK
答案 0 :(得分:1)
与TCP套接字一样,即使UDP套接字也有一个传出(发送)缓冲区。如果该发送缓冲区已满,则即使sendTo()调用也会阻塞。您可以尝试设置SO_SNDBUF套接字选项以增加传出发送缓冲区的大小。另一个原因是你需要解决ARP问题。如果路由中的下一跳或目标本身位于同一子网中且没有ARP条目,则可能发生这种情况。由于ARP解析由ARP请求/ ARP响应组成,因此当您收到ARP响应时,发送方可能已经排队了足够的数据包来填充发送缓冲区。我会尝试逐步增加SO_SNDBUF并查看您遇到的问题是否变得不那么严重 - 这有助于确定发送缓冲区确实是阻塞问题的原因。
这是一个关于设置SO_SNDBUF的链接。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms740476%28v=vs.85%29.aspx
答案 1 :(得分:1)
不要乱用套接字发送缓冲区。没有办法在所有情况下都能做到这一点。
相反,使用非阻塞套接字,并在发送之前检查套接字是否可写。这将允许您在有空间时填充缓冲区。