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:
- How many messages can this receive at one time? What happens if we get more than that?
- Are the messages queued or will they be lost if processing takes too long?
- What does happen if the processing takes too long?
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:
- Does anyone know the answers to the questions above?
- Where would I do some research to find these answers and/or some patterns to follow for this sort of thing?
- What kind of tools could I use to watch the processing for debugging/performance profiling?
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