C# 如何知道UdpClient是否已关闭/处置?
我通过通常的异步回调从UdpClient接收数据:C# 如何知道UdpClient是否已关闭/处置?,c#,asynchronous,dispose,udpclient,C#,Asynchronous,Dispose,Udpclient,我通过通常的异步回调从UdpClient接收数据: private void OnUdpData(IAsyncResult result) { byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint); //Snip doing stuff with data _udpReceive.BeginReceive(OnUdpData, null); } 当我Close()主线程中的UdpClie
private void OnUdpData(IAsyncResult result)
{
byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);
//Snip doing stuff with data
_udpReceive.BeginReceive(OnUdpData, null);
}
当我Close()
主线程中的UdpClient时,回调会像我预期的那样触发,但此时\u udpreceptive
已经被释放,当我尝试调用EndReceive()
时,我会得到一个ObjectDisposedException
。我本来希望得到一个空的缓冲区
正确的处理方法是什么?是否有
UdpClient
的某个成员可以在尝试使用它之前进行检查,或者它是将其全部包装在try{}
中并捕获ObjectDisposedException
的唯一方法?对于正常的收盘来说,这似乎很糟糕。你可以这样做来检查它是否被处理掉了。当UdpClient被释放时,客户端被设置为null
private void OnUdpData(IAsyncResult result)
{
if (_udpReceive.Client == null)
return;
byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);
//Snip doing stuff with data
if (_udpReceive.Client == null)
return;
_udpReceive.BeginReceive(OnUdpData, null);
}
尽管因为您是在一个单独的线程中关闭它,您最终可能会遇到竞争条件。最好只捕获ObjectDisposedException和SocketException
private void OnUdpData(IAsyncResult result)
{
try
{
byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);
//Snip doing stuff with data
_udpReceive.BeginReceive(OnUdpData, null);
}
catch (Exception e)
{
//You may also get a SocketException if you close it in a separate thread.
if (e is ObjectDisposedException || e is SocketException)
{
//Log it as a trace here
return;
}
//Wasn't an exception we were looking for so rethrow it.
throw;
}
}
这完全是出于设计。您做了一些异常的事情,关闭了套接字,即使您希望收到数据。所以你会得到一个例外。NET framework始终确保异步调用已完成,并且在调用EndXxx()时在回调中发出中止原因的信号。好主意,这样可以清除与回调关联的任何状态
通过等待传输完成,停止调用BeginReceive(),然后关闭套接字,可以使其成为非异常。但这并不总是切实可行的,有时你真的想提前终止合同。没问题,只需捕获ObjectDisposedException并退出即可。当然,一定要考虑到手机另一端的应用程序会发生什么。它随后发送的任何内容都将落入比特桶中,无法发现。根据您的问题,听起来您希望避免在强制客户端关闭时抛出异常。我将对您的代码进行一些猜测,并尝试提供一个解决方案: 因为您有一个名为“OnUdpData”的方法,所以我假设您在UDPClient周围有一个包装器类。在该包装类中,您可以执行以下操作:设置一个标志,指示您正在关闭客户机,并且在尝试关闭客户机之前不应再使用该客户机。这避免了在调用
EndReceive()
之前检查\u udprective.Client==null
所导致的争用条件,因为主线程可以在客户端条件检查之后关闭客户端
private bool _finishedListening = false;
public void StopListener()
{
_finishedListening = true;
_udpReceive.Close();
}
private void OnUdpData(IAsyncResult result)
{
if (_finishedListening == true)
return;
byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);
//Snip doing stuff with data
_udpReceive.BeginReceive(OnUdpData, null);
}
回调是否解除了调用
EndReceive
的责任?我的印象是,除了一些不占用资源的IAsyncResult
类型(例如Control.BeginInvoke
的返回值)之外,应该总是在每次BeginXX
之后调用EndXX
。请注意,捕捉到的异常不是EndReceive
操作失败的标志,而是“成功”EndReceive
调用中继导致接收尝试的异常的结果。调用EndX不只是为了从BeginX获取数据吗?不管怎样,在这种情况下,返回是好的。EndReceive将检查相同的内容,并无论如何抛出已处理的异常。