Xortrox
Xortrox

Reputation: 43

Receiving and processing continous packets using UDP

This is my current setup (using UDP):

void OnDataReceived(IAsyncResult result)
{

    IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

    byte[] buffer = socket.EndReceive(result, ref ep);

    Packet p = new Packet(Encoding.ASCII.GetString(buffer, 0, buffer.Length));

    //process packet

    socket.BeginReceive(new AsyncCallback(OnDataReceived), socket);

}

I was wondering what would happen if I immediately call socket.BeginReceive after calling EndReceive and then process the packet to obtain a continous packet flow like this:

void OnDataReceived(IAsyncResult result)
{

    IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

    byte[] buffer = socket.EndReceive(result, ref ep);
    socket.BeginReceive(new AsyncCallback(OnDataReceived), socket);

    Packet p = new Packet(Encoding.ASCII.GetString(buffer, 0, buffer.Length));

    //process packets

}

If a packet is received as soon as I call BeginReceive, would this conflict with the current packet processing somehow?

Also if this would not conflict would changing to TCP make this disfunctional?

Upvotes: 4

Views: 4156

Answers (1)

Jakob Möllås
Jakob Möllås

Reputation: 4379

Looks like you are creating some sort of recursive handler there. I am unsure how that will work, probably not in a good way. I usually go for a separate reader thread that listens to incoming data and passes it on to an event. This has served me well in the past. I have not looked into using async for this though.

Here is some example code on how to use a separate thread to handle incoming UDP data. It is not complete but should give you an idea of how to set it up.

    private Thread _udpReadThread;
    private volatile bool _terminateThread;

    public event DataEventHandler OnDataReceived;
    public delegate void DataEventHandler(object sender, DataEventArgs e);

    private void CreateUdpReadThread()
    {
        _udpReadThread = new Thread(UdpReadThread) { Name = "UDP Read thread" };
        _udpReadThread.Start(new IPEndPoint(IPAddress.Any, 1234));
    }

    private void UdpReadThread(object endPoint)
    {
        var myEndPoint = (EndPoint)endPoint;
        var udpListener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        udpListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        // Important to specify a timeout value, otherwise the socket ReceiveFrom() 
        // will block indefinitely if no packets are received and the thread will never terminate
        udpListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100);
        udpListener.Bind(myEndPoint);

        try
        {
            while (!_terminateThread)
            {
                try
                {
                    var buffer = new byte[1024];
                    var size = udpListener.ReceiveFrom(buffer, ref myEndPoint);
                    Array.Resize(ref buffer, size);

                    // Let any consumer(s) handle the data via an event
                    FireOnDataReceived(((IPEndPoint)(myEndPoint)).Address, buffer);
                }
                catch (SocketException socketException)
                {
                    // Handle socket errors
                }
            }
        }
        finally
        {
            // Close Socket
            udpListener.Shutdown(SocketShutdown.Both);
            udpListener.Close();
        }
    }

    public class DataEventArgs : EventArgs
    {
        public byte[] Data { get; private set; }
        public IPAddress IpAddress { get; private set; }

        public DataEventArgs(IPAddress ipaddress, byte[] data)
        {
            IpAddress = ipaddress;
            Data = data;
        }
    }

Upvotes: 5

Related Questions