在数千个端口号上发送/接收UDP数据包

时间:2013-11-04 20:59:32

标签: c# sockets networking asynchronous udp

我对客户端/服务器应用程序有一系列要求,如下所示:

1)程序向正在侦听预定义UDP端口的主机发送 statuscheck 消息。此消息在OS提供的源端口号上发送。

2)程序需要侦听在步骤1中启动的源端口号,以接收来自远程主机的响应。因此,该计划必须同时收听数千个端口。

3)此过程需要每分钟数千个主机

下面我创建了一个示例示例,它将大量请求发送到Echo Server以模仿此行为。我面临的问题是,虽然我在从远程主机接收数据后关闭每个套接字,但在大约16,000个请求之后会抛出异常,说系统缺少足够的缓冲区空间或队列已满。

实现这些要求的方法是什么?

public void SendChecks()
        {
            IPEndPoint ip = new IPEndPoint(IPAddress.Parse("1.1.1.1"), 7);
            for (int i = 0; i < 200000; i++)
            {

                Socket _UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                stateobject so = new stateobject(_UdpSocket);

                IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
                EndPoint tempRemoteEP = (EndPoint)sender;

                _UdpSocket.Bind(tempRemoteEP);

                string welcome = "Hello";
                byte[] data = new byte[5];
                data = Encoding.ASCII.GetBytes(welcome);

                _UdpSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, ip, new AsyncCallback(OnSend), _UdpSocket);

                //Start listening to the message send by the user
                EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);

                _UdpSocket.BeginReceiveFrom(so.buffer, 0, so.buffer.Length, SocketFlags.None, ref newClientEP, new AsyncCallback(DoReceiveFrom), so);

            }
        }

        private void DoReceiveFrom(IAsyncResult ar)
        {
            try
            {
                stateobject so = (stateobject)ar.AsyncState;

                Socket s = so.sock;

                // Creates a temporary EndPoint to pass to EndReceiveFrom.
                IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
                EndPoint tempRemoteEP = (EndPoint)sender;

                int read = s.EndReceiveFrom(ar, ref tempRemoteEP);

                so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read))
                //All the data has been read, so displays it to the console. 
                string strContent;
                strContent = so.sb.ToString();
                Console.WriteLine(String.Format("Read {0} byte from socket" +"data = {1} ", strContent.Length, strContent));

                s.Close();
                s.Dispose();                    
            }

            catch (Exception ex)
            {                
               Console.WriteLine(ex);  
            }
        }

        private void OnSend(IAsyncResult ira)
        {
            Socket s = (Socket)ira.AsyncState;
            Console.WriteLine("Sent Data To Sever on port {0}",((IPEndPoint)s.LocalEndPoint).Port);

            s.EndSend(ira);
        }
    }

1 个答案:

答案 0 :(得分:1)

我认为在性能和简单性方面最好的方法是在以下任意位置使用单个端口号:

1025 - 65553

然后,当收听来自其他对等方的数千条消息时,它们也会发送到预定义的已知端口号,您可以异步处理它们。

要收听已知的端口号,在本例中为60000:

 mySocket.Bind(new IPEndPoint(IPAddress.Any, 60000));

每次操作后也不要关闭插座!保持打开并重复使用。

正确地说,它将在公园内散步.Net和操作系统来处理您的要求。