gpt4 book ai didi

c# - 如何在循环中使用 UdpClient.BeginReceive

转载 作者:太空狗 更新时间:2023-10-29 18:19:18 26 4
gpt4 key购买 nike

我想做这个

for (int i = 0; i < 100; i++ )
{
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
}

但是我不得不使用 UdpClient.BeginReceive,而不是使用 UdpClient.Receive。问题是,我该怎么做?使用 BeginReceive 的示例并不多,MSDN 示例也没有任何帮助。我应该使用 BeginReceive,还是在单独的线程下创建它?

我一直收到 ObjectDisposedException 异常。我只收到发送的第一个数据。下一个数据将抛出异常。

public class UdpReceiver
{
private UdpClient _client;
public System.Net.Sockets.UdpClient Client
{
get { return _client; }
set { _client = value; }
}
private IPEndPoint _endPoint;
public System.Net.IPEndPoint EndPoint
{
get { return _endPoint; }
set { _endPoint = value; }
}
private int _packetCount;
public int PacketCount
{
get { return _packetCount; }
set { _packetCount = value; }
}
private string _buffers;
public string Buffers
{
get { return _buffers; }
set { _buffers = value; }
}
private Int32 _counter;
public System.Int32 Counter
{
get { return _counter; }
set { _counter = value; }
}
private Int32 _maxTransmission;
public System.Int32 MaxTransmission
{
get { return _maxTransmission; }
set { _maxTransmission = value; }
}

public UdpReceiver(UdpClient udpClient, IPEndPoint ipEndPoint, string buffers, Int32 counter, Int32 maxTransmission)
{
_client = udpClient;
_endPoint = ipEndPoint;
_buffers = buffers;
_counter = counter;
_maxTransmission = maxTransmission;
}
public void StartReceive()
{
_packetCount = 0;
_client.BeginReceive(new AsyncCallback(Callback), null);
}

private void Callback(IAsyncResult result)
{
try
{
byte[] buffer = _client.EndReceive(result, ref _endPoint);
// Process buffer
MainWindow.Log(Encoding.ASCII.GetString(buffer));
_packetCount += 1;
if (_packetCount < _maxTransmission)
{
_client.BeginReceive(new AsyncCallback(Callback), null);
}
}
catch (ObjectDisposedException ex)
{
MainWindow.Log(ex.ToString());
}
catch (SocketException ex)
{
MainWindow.Log(ex.ToString());
}
catch (System.Exception ex)
{
MainWindow.Log(ex.ToString());
}
}
}

什么给了?

顺便说一下,总体思路是:

  1. 创建 tcpclient 管理器。
  2. 开始使用 udpclient 发送/接收数据。
  3. 当所有数据发送完毕后,tcpclient 管理器将向接收方发送所有数据已发送的信号,udpclient 连接应关闭。

最佳答案

似乎 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 以确定在执行 UdpClient.Receive() 之前是否有任何 UDP 请求排队- 这完全消除了阻塞方面。我确实建议您谨慎尝试此操作,因为此行为并未出现在 Microsoft 文档中,但似乎确实有效。

注意:

MSDN exmaple code您可能已经发现,在研究此问题时需要额外的 user defined class - Udp状态。这不是 .NET 库类。这似乎让很多人在研究这个问题时感到困惑。

timeouts不必严格设置为使您的应用程序完全退出,但它们将允许您在该循环中做其他事情,而不是永远阻塞。

listener.Close()命令很重要,因为它强制 UdpClient 抛出异常并退出循环,从而允许处理 Thread.Abort()。如果没有这个,您可能无法正确终止监听器线程,直到它超时或收到 UDP 数据包导致代码继续通过 UdpClient.Receive() block 。


为了补充这个无价的答案,这里有一个有效且经过测试的代码片段。 (这里是在 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");
}

关于c# - 如何在循环中使用 UdpClient.BeginReceive,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4118219/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com