I feel, that I am misunderstanding something about async sockets in .Net. The situation is as follows : I have 1 async socket client and 1 async socket server. They communicate without any visible problems, but when I close listener and disconnect clients, the "OnConnectRequest" which is bound to "BeginAccept" as a callback, still gets called at least once. The "BeginReceive", "OnConnectRequest", "Disconnect" and "Dispose" methods are :
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);
}
}
What I am doing is calling "Dispose" to closes listener and shut down all client sockets. The client is then still active, and it tries to reconnect, but what I expected to happen was server being completely unavailable on corresponding IP and port. What I see instead is "OnConnectRequest" callback being called, which crashes because of attempt to use already disposed socket. Can you please explain, what is wrong here, and how graceful shutdown of a listener and all accepted connections should look like ?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…