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

4
这是我目前的设置(使用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个回答

5

看起来你正在创建一种递归处理程序。我不确定那样会如何工作,可能效果不佳。我通常会选择一个独立的读取器线程来监听传入的数据并将其传递给事件。这在过去为我服务过。不过,我还没有研究过如何使用async。

以下是一些示例代码,演示如何使用单独的线程来处理传入的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;
        }
    }

1
那似乎是一个有效的答案,但由于我的声望只有11,我无法投票支持它。我目前使用的方法是Socket.BeginReceive,当接收到数据时,它调用绑定在新AsyncCallback参数中的函数。(我相信这允许当前对OnDataReceived的调用完成,同时能够监听新数据) 我的主要担忧可能有点傻,但我担心当多个线程同时执行1个函数的多个调用时会发生什么。 - Xortrox
实际上不用理会那个了,我已经找到解决方法了: https://dev59.com/bWkv5IYBdhLWcg3wnCLH - Xortrox
1
这不会导致很多不必要的内存重新分配吗?您在循环每次通过时都分配缓冲区,无论它是否被使用。 - Loren Pechtel
1
是的,您可以通过仅在接收到某些内容时进行分配来稍微优化这些内容。 - Jakob Möllås

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接