Reputation: 90
I have a set of requirements for a client/server application as listed below:
1) Program sends a statuscheck message to a host which is listening on a predefined UDP port. This message is sent on a source port number given by the OS.
2) The program needs to listen on the source port number initiated in step 1 to receive the response from the remote host. The program therefore must listen on thousands of port at the same time.
3) This process needs to be done for thousands of hosts per minute
Below I've created a sample example that sends a large number of requests to an Echo Server to mimic this behaviour. The problem that I'm facing is that although I close each socket after receiving data from the remote host, after about 16,000 requests an exception is thrown saying system lacked sufficient buffer space or queue was full.
What would be a way to achieve such requirements?
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);
}
}
Upvotes: 0
Views: 1601
Reputation: 11426
I think the best way to go in terms of performance and simplicity would be to simply use a single port number anywhere between:
1025 - 65553
Then when listening for thousands of messages from other peers they also send to a predefined known port number and you can process them asynchronously.
To listen to a known port number, in this case 60000:
mySocket.Bind(new IPEndPoint(IPAddress.Any, 60000));
Also do not close the socket after each operation! Keep it open and re-use it.
Properly written it would be walk in the park for .Net and the OS to handle your requirements.
Upvotes: 1