处理异步套接字(.Net)后,仍会调用回调函数

我觉得,我误解了.Net中的异步套接字。 情况如下:我有1个异步套接字客户端和1个异步套接字服务器。 它们在没有任何可见问题的情况下进行通信,但是当我关闭侦听器并断开客户端时,绑定到“BeginAccept”作为回调的“OnConnectRequest”仍然至少被调用一次。 “BeginReceive”,“OnConnectRequest”,“Disconnect”和“Dispose”方法是:

public void BeginReceive() { _listener.Bind(_endpoint); _listener.Listen(_maxConnections); try { _listener.BeginAccept(new AsyncCallback(OnConnectRequest), _listener); } catch (SocketException se) { OnListeningError(this, new Exception("Server cannot accept connections due to network shutdown or some fatal failure", se)); } } protected void OnConnectRequest(IAsyncResult ar) { Socket listener = (Socket)ar.AsyncState; Socket client = listener.EndAccept(ar); var remoteEndpoint = client.RemoteEndPoint; IDuplexStateObject state = new DuplexStateObject(); state.WorkSocket = client; if (_clients.Count <= _maxConnections) { lock (_clients) { _clients.Add(state); } OnConnected(this, state); } else { //denying connection client.Close(); AcceptingError(this, null, new Exception(string.Format("Maximal connection count reached, connection attempt {0} has been denied", (remoteEndpoint != null) ? remoteEndpoint.ToString() : null))); } //accept connections from other clients try { listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener); } catch (SocketException se) { if (se.SocketErrorCode == SocketError.TooManyOpenSockets) { OnListeningError(this, new Exception("Maximal connection count reached, not possible to create any more connections")); } else { OnListeningError(this, new Exception("Server cannot accept connections due to network shutdown or some fatal failure")); } } } public void Disconnect(IStateObject state) { if (state.WorkSocket == null) { //OnDisconnectError(this, state.ClientInfo, // new Exception("No underlying work socket found for client. Already disconnected, disposing connection...")); OnDisconnected(this, state.ClientInfo); return; } try { if (state.WorkSocket.Connected) { state.WorkSocket.Shutdown(SocketShutdown.Both); } state.WorkSocket.Close(); } catch (SocketException se) { OnDisconnectError(this, state.ClientInfo, se); } OnDisconnected(this, state.ClientInfo); lock (_clients) { _clients.Remove(state); } } public void Dispose() { _listener.Close(); //keys are cloned before disconnecting foreach (var client in _clients.ToList()) { Disconnect(client); } } 

我正在做的是调用“Dispose”来关闭监听器并关闭所有客户端套接字。 然后客户端仍处于活动状态,并尝试重新连接,但我预计会发生的是服务器在相应的IP和端口上完全不可用。 我所看到的是调用“OnConnectRequest”回调,由于尝试使用已经设置的套接字而崩溃。 你能解释一下,这里有什么问题,以及听众和所有接受的连接的优雅关闭应该如何?

不,这是正确的 – 即使关闭套接字,也会始终调用您在Begin...操作中指定的回调(如果关闭套接字,则会因此调用它)。 您应该捕获EndAccept上的EndAccept ,然后返回而无需进一步操作。 关闭/部署套接字/侦听器是取消对其进行异步操作的唯一方法。 ( EndAccept也可以生成SocketException ,应该正常处理。)

使用自己维护的标志来检查监听器是否仍然可用是要求麻烦,因为您引入了需要同步的共享状态(易失性读取等)。 你可以通过这种方式轻松介绍种族条件。 监听器已在内部为您维护这样一个标志,它用于抛出ObjectDisposedException ,所以我只是使用它。 确实,在正常情况下捕获ObjectDisposedException是编码错误的可能标志(因为你应该知道何时放置一个对象),但是使用异步代码它是非常标准的。