循环中的C#Socket.SendTo最终导致SocketException(取决于路由器)

时间:2011-08-13 01:52:20

标签: c# sockets sendto


我正在做一些基本的Socket消息传递。我有一个运行良好的例程,但是在负载下存在问题。

我正在使用UDP来执行无连接的SendTo,基本上执行类似ping操作,以查看我的任何侦听器是否在局域网上。理想情况下,我只会使用广播地址,但无线路由器似乎不会转发我的广播。我的工作是迭代子网上的所有IP并将我的数据克发送到每个IP。其他PC正在收听,如果他们收到消息,他们会回复,这就是我让Peers找到对方的方式。以下是循环中的代码,它将数据gram发送到子网中的每个IP。

            string msgStr = "some message here...";
            byte[] sendbuf = Encoding.ASCII.GetBytes(msgStr);

            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.Blocking = true;
            socket.SendTo(sendbuf, remoteEndPt);
            //socket.Close();

这是有效的,但是当子网范围很大时,比如255.255.0.0(意味着要迭代~60,000个IP),我最终会得到一个错误代码为“10022”的SocketException,意思是“无效的参数”。在大约10,000次成功发送之后,这往往会发生,然后我开始看到这个错误。此外,我在工作中使用的路由器处理它并且可能是一个高功率路由器,但是我实验室中的廉价路由器是产生错误的路由器。

如果我在捕获SocketException之后等待一段时间并且在恢复循环之前它通常会恢复,但最终我会再次收到错误。

我认为发生的事情是路由器上的缓冲区已满,我无法再发送数据。工作中质量较高的人可以处理它,但廉价的人却陷入困境。听起来有道理吗?

几个问题:

1)以无连接方式使用SendTo时,是否需要在Socket上调用Close()?

我没有看到调用Close()的任何好处,但是当我调用Close()时,它会严重减慢我的迭代速度(我上面已经注释掉它因为它确实减慢了很多事情)。这有意义吗?

2)有没有办法告诉我在尝试发送更多数据之前应该等待?仅仅捕获异常并不正确,我仍然不知道它的原因是什么。

谢谢,J。

1 个答案:

答案 0 :(得分:2)

我不确定那只是路由器,但我怀疑你在操作系统中遇到了一些限制......

您每次发送时都有Socket创建的原因吗? 只需重复使用它......

无论如何,根据http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx,最好在Shutdown()上拨打Close()然后Socket ...也许不是每次发送,而是每255个IP或所以...

结帐UdpClient - 这可以使实施更容易/更健壮

编辑 - 根据评论

如果你想要一个Socket重用“缓存”...例如,这将确保每256次检查只使用一个特定的Socket ......

// build/fill your Socket-Queue for example in the con
class SocketExample
{
    Queue<Socket> a = new Queue<Socket>();
    SocketExample ()
    {
        int ii = 0, C = 256;
        for (ii = 0; ii < C; C++)
        {
            a.Enqueue (new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp));
        }
    }

    // in your function you just dequeue a Socket and use it, 
    // after you are finished you enqueue it
    void CheckNetIP (some parameters...)
    {
        Socket S = a.Dequeue();
        // do whatever you want to do...
        // IF there is no exception
        a.Enqueue(S); 
    }
}