Reputation: 647
Okay, this is my first stack overflow question so please feel free to suggest better ways to ask or what I should include next time. Most of the time I can Google to get my answers but this one is a little trickier...
I am writing a windows application in C# that listens on a UDP port and then process the incoming UDP messages. More specifically, I am using the UDPClient
class and listening using the BeginReceive method. The receive callback is in turn firing it's own message received event and then resetting the UDP client again. This "MessageReceived" event is subsequently handled by a processor object.
I thought that was all pretty smart until my manager posed some questions to me such as:
We cannot be losing the messages because the last one was still processing, and we can't be building up until the system crashes because it's out of memory either. What he would like to hear (and rightfully so) is some sort of verification that there is a deterministic way to deal with a "storm" of messages. Unfortunately, I have no idea where to go with this to get an answer. I have included what I think is the relevant code below.
So:
If I have made a huge mistake in my design, what should I do to sort it out (i.e. introduce a queue, use a thread pool etc)?
public void ReceiveCallback(IAsyncResult ar)
{
//Cast the item back to the listener
UdpListener listener = (UdpListener)ar.AsyncState;
//If we are supposed to be listening, then get the data from the socket
//Listen is false during shutdown
if (Listen)
{
//The try catch is placed inside the listen loop so that if there is an error in the processing it will
//recover and listen again. this may cause more exceptions but we can be sure that it will not
// stop listening without us knowing
try
{
//Address and port from the external system
IPEndPoint ep = listener.EndPoint;
//Get the data from the async read
Byte[] receiveBytes = listener.Client.EndReceive(ar, ref ep);
//Reset the socket to listen again
listener.Client.BeginReceive(new AsyncCallback(ReceiveCallback), listener);
//Execute the event to pass external components the message
HeartbeatEventArgs hea = new HeartbeatEventArgs(DateTime.Now, ep, receiveBytes);
OnHeartbeatReceived(hea);
//Ack back to the external system
HeartbeatAcknowledgement(new IPEndPoint(ep.Address, ep.Port), receiveBytes);
}
catch (Exception e)
{
log.Error(e.Message);
//Reset the socket to listen again
}
}
}
listner is just a wrapper around UDPClient
. As follows:
#region UdpClient Wrapper (UdpListener)
/// <summary>
/// UdpListener is used to control the asynchronous processing of a UDPClient object.
/// </summary>
public class UdpListener
{
/// <summary>
/// IPEndpoint on which to accept a connection. Usually set to "Any".
/// </summary>
public IPEndPoint EndPoint { get; set; }
/// <summary>
/// The socket based client object that is used for communication
/// </summary>
public UdpClient Client { get; set; }
public UdpListener(int port)
{
EndPoint = new IPEndPoint(IPAddress.Any, port);
Client = new UdpClient(EndPoint);
}
}
#endregion
Thanks,
Dinsdale
Upvotes: 2
Views: 3573
Reputation: 11190
If losing messages is a concern, then UDP isn't for you. UDP guarantees only that if the message arrives, it will be complete. It does not guarantee message order or delivery. In other words, if a client sends two messages, you might receive them out of order, or only the first, or only the last (or none at all). If you need to guarantee delivery and order, use TCP instead (TCP comes with it's own set of guarantees and gotchas).
With regard how many messages it can process, you will have an upper limit. If you aren't processing messages faster than they are arriving, then they will be queued, either in your application layer or in the UDP networking layer. Once the network buffers are full, your network interface will simply begin throwing away messages.
Upvotes: 1