使用udpClient连续接收消息

27

我在寻找使用 C# 中的 UdpClient 类接收和处理消息的最佳解决方案。请问有人有相关的解决方案吗?


4
你到目前为止尝试了什么?你不喜欢它的哪些地方/让你相信有一个“更好”的解决方案? - dtb
3个回答

46

尝试使用以下代码:

//Client uses as receive udp client
UdpClient Client = new UdpClient(Port);

try
{
     Client.BeginReceive(new AsyncCallback(recv), null);
}
catch(Exception e)
{
     MessageBox.Show(e.ToString());
}

//CallBack
private void recv(IAsyncResult res)
{
    IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 8000);
    byte[] received = Client.EndReceive(res, ref RemoteIpEndPoint);

    //Process codes

    MessageBox.Show(Encoding.UTF8.GetString(received));
    Client.BeginReceive(new AsyncCallback(recv), null);
}

25
需要翻译的内容:+1:有几点需要注意。首先,在异步回调中使用 MessageBox.Show 进行错误处理可能不是一个好主意,但我假设你只是举个例子。其次,在处理数据项之前立即调用下一个 BeginReceive 可能更好——而不是在处理数据项之后再调用。否则,当您处理数据时可能会错过到达的消息。当然,这时您的异步回调必须是可重入的(即线程安全的),但它本来就应该是这样的。 - Jim Mischel
这段代码是否适用于多个客户端异步发送请求的情况?我陷入了同样的问题中,需要编写适用于多个客户端的代码。这是我的问题链接 http://stackoverflow.com/questions/32837887/udp-client-server - SANDEEP
1
什么是 recv - EgoPingvina
私有的 void recv(IAsyncResult res) - Matteo TeoMan Mangano
@JimMischel非常感谢您提出可重入性问题。在某些情况下,我收到了相同数据包的两个副本,有时甚至是不完整的数据包,直到我保护我的EndReceive回调免受可重入性影响。 - henon
显示剩余3条评论

22

对于使用TAP而非Begin/End方法的较新技术,您可以在.NET 4.5中使用以下方法

非常简单!

异步方法

    private static void UDPListener()
    {
        Task.Run(async () =>
        {
            using (var udpClient = new UdpClient(11000))
            {
                string loggingEvent = "";
                while (true)
                {
                    //IPEndPoint object will allow us to read datagrams sent from any source.
                    var receivedResults = await udpClient.ReceiveAsync();
                    loggingEvent += Encoding.ASCII.GetString(receivedResults.Buffer);
                }
            }
        });
    }

同步方法

与上述的异步方法相反,这也可以以非常类似的方式实现同步方法:

    private static void UDPListener()
    {
        Task.Run(() =>
        {
            using (var udpClient = new UdpClient(11000))
            {
                string loggingEvent = "";
                while (true)
                {
                    //IPEndPoint object will allow us to read datagrams sent from any source.
                    var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                    var receivedResults = udpClient.Receive(ref remoteEndPoint);
                    loggingEvent += Encoding.ASCII.GetString(receivedResults);
                }
            }
        });
    }

1
是的,这个程序可能可以运行。但是考虑到像Unity 3D这样的环境,你没有多任务/多线程的功能。在这种情况下,你该怎么办? - Slesa
在 .net 3.5 中是否有类似于 Task.Run 的等效方法? - Nyerguds
3
回复有点晚了,但在Unity中可以使用多任务/多线程。您只需要在主线程上访问Unity相关内容,其他所有操作都可以在其他线程上完成。 - Alexander
2
你有没有想过为什么ReceiveAsync方法中缺少IPEndPoint?如果要向发送者发送消息,你会怎么做? - scape
1
@scape将在结果UdpReceiveResult->RemoteEndPoint中。 在同步方法中,传递RemoteEndPoint参数时使用"ref"并非徒劳无功。 - Gardes

0

我可以推荐两个关于这个解决方案的链接,对我很有帮助。

PC 相关

Stack Overflow

第一个链接提供了一个非常简单的解决方案,但是在修改时要小心,因为只有在首先向“远程”设备发送某个 UDP 数据包后,连续接收才能正常工作。 为了持续监听,请在每次读取传入数据后添加代码行“udp.BeginReceive(new AsyncCallback(UDP_IncomingData), udp_ep);”,以启用新的 UDP 数据包接收。

第二个链接提供了一种使用多播 IP 地址(239.255.255.255 - 240.0.0.0)的好方法。


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