我正在实现一个简单的本地网络发现协议,所以我调用UdpClient.Send然后调用UdpClient.BeginReceive。如果有多个响应挂起,我会在回调结束时调用UdpClient.BeginReceive。像这样:
UdpClient client = new UdpClient(AddressFamily.InterNetwork);
client.EnableBroadcast = true;
client.Send(request, request.Length, broadcastEndPoint);
client.BeginReceive(Callback, client);
...然后在Callback
:
void Callback(IAsyncResult ar)
{
UdpClient client = (UdpClient)ar.AsyncState;
IPEndPoint remoteEndPoint = null;
byte[] response = client.EndReceive(ar, ref remoteEndPoint);
// Do something with response
client.BeginReceive(Callback, client);
}
我的问题是我的主循环调用client.Close
,而仍有待处理的接收。接收完成,然后我对BeginReceive的下一次调用抛出异常:System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
为什么UdpClient没有CancelReceive方法?我该怎么做呢?
答案 0 :(得分:6)
相反或要克服此异常创建bool并在发出close命令之前设置它,使用该bool检入回调
像这样bool isClosing=false;
void Callback(IAsyncResult ar)
{
if(isClosing) return;
}
在发出关闭命令
之前设置bool
isClosing
答案 1 :(得分:3)
使用“isClosing”标志通知回调函数UdpClient不再可用不是一个合适的解决方案。回调在不同的线程中执行,在“isClosing”标志检查之后和“BeginReceive”(或“EndReceive”)调用之前总是有可能关闭连接。
即使这不是一个干净的设计,微软似乎建议只捕获相应的异常,以检测套接字不再可用。 “BeginReceive”没有记录,但那是documented for the similar function "BeginConnect":
要取消对BeginConnect()方法的挂起调用,请关闭 插座。在异步时调用Close()方法时 操作正在进行中,提供给BeginConnect()的回调 方法被调用。随后调用EndConnect(IAsyncResult) 方法将抛出一个ObjectDisposedException来指示 操作已被取消。
因此,示例代码如下所示:
void Callback(IAsyncResult ar)
{
try
{
UdpClient client = (UdpClient)ar.AsyncState;
IPEndPoint remoteEndPoint = null;
byte[] response = client.EndReceive(ar, ref remoteEndPoint);
// Do something with response
client.BeginReceive(Callback, client);
}
catch (SocketException e)
{
// Oups, connection was closed
}
catch (ObjectDisposedException e)
{
// Oups, client was disposed
}
}