使用UDP接收和处理连续数据包

时间:2012-12-01 13:40:19

标签: c# .net sockets udp asynccallback

这是我当前的设置(使用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);

}

我想知道如果我在调用EndReceive之后立即调用socket.BeginReceive然后处理数据包以获得这样的连续数据包流会发生什么:

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

}

如果我在调用BeginReceive时收到数据包,是否会以某种方式与当前数据包处理冲突?

此外,如果这不会发生冲突会改变为TCP会导致此功能失效吗?

1 个答案:

答案 0 :(得分:5)

看起来你正在那里创建某种递归处理程序。我不确定这是如何工作的,可能不是很好。我通常会选择一个单独的读取器线程来侦听传入的数据并将其传递给事件。这对我来说过去很好。我没有考虑过使用异步。

以下是有关如何使用单独线程处理传入UDP数据的示例代码。它不完整,但应该让你知道如何设置它。

    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;
        }
    }