它似乎UdpClient.BeginReceive()
并UdpClient.EndReceive()
没有得到很好的实施/理解.当然,与TcpListener的实现方式相比,使用起来要困难得多.
您可以采取一些措施来UdpClient.Receive()
更好地利用这项工作.首先,在底层套接字客户端上设置超时将使控制能够通过(到异常),允许控制流继续或循环播放.其次,在一个新的线程(其中我还没有创建)创建UDP监听,你可避免的半阻挡作用UdpClient.Receive()
的功能,如果你这样做是正确,你可以有效地中止该线程以后.
以下代码分为三部分.第一个和最后一个部分应分别位于入口和出口点的主循环中.第二部分应该在您创建的新线程中.
一个简单的例子:
// Define this globally, on your main thread UdpClient listener = null; // ... // ... // Create a new thread and run this code: IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 9999); byte[] data = new byte[0]; string message = ""; listener.Client.SendTimeout = 5000; listener.Client.ReceiveTimeout = 5000; listener = new UdpClient(endPoint); while(true) { try { data = listener.Receive(ref endPoint); message = Encoding.ASCII.GetString(data); } catch(System.Net.Socket.SocketException ex) { if (ex.ErrorCode != 10060) { // Handle the error. 10060 is a timeout error, which is expected. } } // Do something else here. // ... // // If your process is eating CPU, you may want to sleep briefly // System.Threading.Thread.Sleep(10); } // ... // ... // Back on your main thread, when it's exiting, run this code // in order to completely kill off the UDP thread you created above: listener.Close(); thread.Close(); thread.Abort(); thread.Join(5000); thread = null;
除此之外,您还可以检查UdpClient.Available > 0
以确定在执行之前是否有任何UDP请求排队UdpClient.Receive()
- 这完全消除了阻塞方面.我建议您谨慎尝试,因为此行为不会出现在Microsoft文档中,但似乎确实有效.
注意:
您在研究此问题时可能找到的MSDN exmaple代码需要一个额外的用户定义类 - UdpState.这不是.NET库类.在研究这个问题时,这似乎让很多人感到困惑.
该超时不必严格进行设置,以使您的应用程序完全退出,但他们会允许你做其他事情在这个循环,而不是永远阻塞.
该listener.Close()命令是非常重要的,因为它迫使UdpClient抛出一个异常,并退出循环,使Thread.Abort的()得到处理.如果没有这个,您可能无法正常终止侦听器线程,直到它超时或收到UDP数据包导致代码继续通过UdpClient.Receive()块.
只是为了补充这个无价的答案,这是一个经过实践检验的代码片段.(这里是Unity3D上下文,但当然对于任何c#.)
// minmal flawless UDP listener per PretorianNZ using System.Collections; using System; using System.Net.Sockets; using System.Net; using System.Threading; void Start() { listenThread = new Thread (new ThreadStart (SimplestReceiver)); listenThread.Start(); } private Thread listenThread; private UdpClient listenClient; private void SimplestReceiver() { Debug.Log(",,,,,,,,,,,, Overall listener thread started."); IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Any, 1260); listenClient = new UdpClient(listenEndPoint); Debug.Log(",,,,,,,,,,,, listen client started."); while(true) { Debug.Log(",,,,, listen client listening"); try { Byte[] data = listenClient.Receive(ref listenEndPoint); string message = Encoding.ASCII.GetString(data); Debug.Log("Listener heard: " +message); } catch( SocketException ex) { if (ex.ErrorCode != 10060) Debug.Log("a more serious error " +ex.ErrorCode); else Debug.Log("expected timeout error"); } Thread.Sleep(10); // tune for your situation, can usually be omitted } } void OnDestroy() { CleanUp(); } void OnDisable() { CleanUp(); } // be certain to catch ALL possibilities of exit in your environment, // or else the thread will typically live on beyond the app quitting. void CleanUp() { Debug.Log ("Cleanup for listener..."); // note, consider carefully that it may not be running listenClient.Close(); Debug.Log(",,,,, listen client correctly stopped"); listenThread.Abort(); listenThread.Join(5000); listenThread = null; Debug.Log(",,,,, listener thread correctly stopped"); }