【问题标题】:How to implement UDP without blocking main thread如何在不阻塞主线程的情况下实现UDP
【发布时间】:2019-11-01 16:23:28
【问题描述】:

我使用的数据通过 UDP 到达。我想在不阻塞主线程的情况下创建几个 UDP 连接。我已经同步和异步地实现了 UDP 连接,但是它们都保持主线程锁定。我的代码永远不会到达 'Console.WriteLine("Past the Async")'

目标是让 UDP 连接在后台运行。

谁能提供一些关于下一步要尝试什么,或者如何正确实现允许主线程仍然接收命令的异步版本的 UDP 的指导?

我将异步版本的 ReceiveUdpData() 注释掉。

class Program
{
    // The whole point of this is to not block the main thread.  
    static async Task Main(string[] args)
    {
        ReceiveUdpData();
        Console.WriteLine("Past Receive UDP Data");

        await foreach (var item in MessagesAsync())
        {
            Console.WriteLine(item);
        }
        Console.WriteLine("Past The Async");

    }
    // Synchronous connection to UDP.
    public static void ReceiveUdpData()
    {
        IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        var count = 0;
        using (UdpClient client = new UdpClient(12345))
        {
            while (true)
            {
                Byte[] receiveBytes = client.Receive(ref remoteEndPoint);
                count++;
                Console.WriteLine(count);
            }
        }
    }
    // Async UDP connection
    private static async IAsyncEnumerable<object> MessagesAsync()
    {
        IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        var count = 0;
        using (UdpClient client = new UdpClient(12345))
        {
            while (true)
            {
                UdpReceiveResult test = await client.ReceiveAsync();
                count++;
                yield return test.ToString();
            }
        }
    }
}

【问题讨论】:

    标签: c# multithreading asynchronous udp


    【解决方案1】:

    await 将通过调度方法的其余部分在给定任务继续后运行来“阻止”当前方法。它有点相似(在语义上与Task.ContinueWith 不同)所以csharp Console.WriteLine("Past The Async") 将仅在收到所有消息后执行。

    您不能通过以“即发即弃”的方式枚举单独任务上的 IAsyncEnumerable 来等待消息:

    static async Task Main(string[] args)
    {
       PrintMessages();
    
       Console.WriteLine("Past The Async");
    }
    
    public static async Task PrintMessages()
    {
       await foreach (var item in MessagesAsync())
       {
           Console.WriteLine(item);
       }
    }
    

    但如果你这样做,你的程序将在Main 退出时立即终止,所以你可能真的想等待,或者你可能还有其他工作可以执行。

    【讨论】:

    • 谢谢 Claudiu,我将 Console.ReadLine() 放在 Main 的末尾,以保持一切正常运行。
    【解决方案2】:

    这是我用来使用异步 udp 的程序的基础:

    样本:

    using System;
    using System.Net.Sockets;
    using System.Net;
    
    class Program {
        static void OnUpdateData(IAsyncResult result) {
            UdpClient socket = result.AsyncState as UdpClient;
            IPEndPoint source = new IPEndPoint(0, 0);
            byte[] message = socket.EndReceive(result, ref source);
    
            Console.WriteLine($"Received {message.Length} bytes from {source}");
            // schedule the next receive operation once reading is done:
            socket.BeginReceive(new AsyncCallback(OnUpdateData), socket);
        }
        static void Main(string[] args) {
            UdpClient socket = new UdpClient(12345); 
            socket.BeginReceive(new AsyncCallback(OnUpdateData), socket);
    
            //send message with same program or use another program
            IPEndPoint target = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
            // send a couple of sample messages:
            for (int num = 1; num <= 3; num++) {
                byte[] message = new byte[num];
                socket.Send(message, message.Length, target);
            }
            Console.ReadKey();
        }
    }
    

    【讨论】:

    • 感谢您的反馈。我将花一些时间在整个星期内分析您的解决方案,看看它是否是一个更好的设置。
    猜你喜欢
    • 2020-01-26
    • 2017-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    相关资源
    最近更新 更多