C# 在数千个端口号上发送/接收UDP数据包
我对客户机/服务器应用程序有一系列要求,如下所示: 1) 程序向正在侦听预定义UDP端口的主机发送statuscheck消息。此消息通过操作系统提供的源端口号发送 2) 程序需要监听在步骤1中启动的源端口号,以接收来自远程主机的响应。因此,程序必须同时监听数千个端口 3) 每分钟需要对数千台主机执行此过程 下面我创建了一个示例,它向Echo服务器发送大量请求来模拟这种行为。我面临的问题是,尽管我在从远程主机接收数据后关闭了每个套接字,但在大约16000个请求之后,会抛出一个异常,表示系统缺少足够的缓冲区空间或队列已满 实现这些要求的方法是什么C# 在数千个端口号上发送/接收UDP数据包,c#,sockets,networking,asynchronous,udp,C#,Sockets,Networking,Asynchronous,Udp,我对客户机/服务器应用程序有一系列要求,如下所示: 1) 程序向正在侦听预定义UDP端口的主机发送statuscheck消息。此消息通过操作系统提供的源端口号发送 2) 程序需要监听在步骤1中启动的源端口号,以接收来自远程主机的响应。因此,程序必须同时监听数千个端口 3) 每分钟需要对数千台主机执行此过程 下面我创建了一个示例,它向Echo服务器发送大量请求来模拟这种行为。我面临的问题是,尽管我在从远程主机接收数据后关闭了每个套接字,但在大约16000个请求之后,会抛出一个异常,表示系统缺少足够
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);
}
}
publicsvoidsendchecks()
{
IPEndPoint ip=新的IPEndPoint(IPAddress.Parse(“1.1.1.1”),7);
对于(int i=0;i<200000;i++)
{
Socket _UdpSocket=新套接字(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
stateobject so=新的stateobject(_UdpSocket);
IPEndPoint发送方=新IPEndPoint(IPAddress.Any,0);
端点tempRemoteEP=(端点)发送方;
_UdpSocket.Bind(tempRemoteEP);
string welcome=“Hello”;
字节[]数据=新字节[5];
数据=Encoding.ASCII.GetBytes(欢迎使用);
_UdpSocket.BeginSendTo(数据,0,数据.长度,SocketFlags.None,ip,新的异步回调(OnSend),\u UdpSocket);
//开始收听用户发送的消息
EndPoint newClientEP=新的IPEndPoint(IPAddress.Any,0);
_UdpSocket.BeginReceiveFrom(so.buffer,0,so.buffer.Length,SocketFlags.None,ref newClientEP,new AsyncCallback(DoReceiveFrom),so);
}
}
私人无效或接收自(IAsyncResult ar)
{
尝试
{
stateobject so=(stateobject)ar.AsyncState;
插座s=so.sock;
//创建要传递给EndReceiveFrom的临时端点。
IPEndPoint发送方=新IPEndPoint(IPAddress.Any,0);
端点tempRemoteEP=(端点)发送方;
int read=s.EndReceiveFrom(ar,ref tempRemoteEP);
so.sb.Append(Encoding.ASCII.GetString(so.buffer,0,read))
//所有数据都已读取,因此将其显示到控制台。
字符串结构内容;
strContent=so.sb.ToString();
WriteLine(String.Format(“从套接字“+”数据={1}”读取{0}字节,strContent.Length,strContent));
s、 Close();
s、 处置();
}
捕获(例外情况除外)
{
控制台写入线(ex);
}
}
私人无效支出(IAsyncResult ira)
{
套接字s=(套接字)ira.AsyncState;
WriteLine(“已将数据发送到端口{0}上的服务器,((IPEndPoint)s.LocalEndPoint).port);
s、 EndSend(ira);
}
}
我认为,就性能和简单性而言,最好的方法是在以下任意位置使用一个端口号:
1025 - 65553
然后,当侦听来自其他对等方的数千条消息时,它们也会发送到预定义的已知端口号,您可以异步处理它们
要侦听已知端口号(在本例中为60000),请执行以下操作:
mySocket.Bind(new IPEndPoint(IPAddress.Any, 60000));
每次操作后也不要关闭插座!保持打开状态并重复使用
如果写得好,这将是.Net和操作系统处理您的需求的最佳选择。您正试图以.Net允许的速度发送200000个请求,同时尝试聆听200000个响应。我怀疑操作系统能处理这个问题?考虑到这些要求,你会建议我怎么做?需要多长时间才能发出16000个请求并发生异常?我认为.NET可以以比网络发送更快的速度对它们进行排队,如果发生这种情况,您将以某种方式耗尽资源。如果您对预期的负载类型有一个估计,请在上面限制该测试程序以达到该速率,而不是在尽可能短的时间内完成尽可能多的操作。引发异常需要将近13秒的时间。问题是,当还有更多可用端口时,它为什么会耗尽资源?当异常发生时,系统上有足够的ram。是的,这将是另一种选择。我可以在一个套接字上发送数千个请求并同时侦听。但是考虑到问题的要求,我希望能为我的问题找到一个解决方案。到底什么系统会要求您在每次发送时使用不同的端口号?传统系统往往有特定的要求。看看您的问题,我的答案会符合您的要求-而不是依赖操作系统提供的端口发送发送您指定的端口!远程同行不会介意的!如果您确实想使用随机端口,您仍然可以使用相同的套接字,并在Winsock套接字上使用pinvoke来欺骗源端口。