我觉得,我误解了.Net中的异步套接字。情况如下:我有1个异步套接字客户端和1个异步套接字服务器。他们在没有任何明显问题的情况下进行通信,但是当我关闭监听器并断开客户端连接时," OnConnectRequest"这是绑定到" BeginAccept"作为回调,仍然至少被调用一次。 " BeginReceive"," OnConnectRequest","断开"和"处理"方法是:
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);
}
}
我正在做的是打电话&#34; Dispose&#34;关闭监听器并关闭所有客户端套接字。然后客户端仍处于活动状态,并尝试重新连接,但我预计会发生的是服务器在相应的IP和端口上完全不可用。我所看到的是&#34; OnConnectRequest&#34;被调用的回调,由于尝试使用已经设置的套接字而崩溃。你能解释一下,这里有什么问题,以及听众和所有接受的连接的优雅关闭应该是什么样的?
答案 0 :(得分:1)
不,这是正确的 - 您在Begin...
操作中指定的回调将总是被调用,即使您关闭套接字(如果您关闭套接字,它将是叫,因为。你应该抓住你ObjectDisposedException
上的EndAccept
,然后返回而不采取进一步行动。关闭/部署套接字/侦听器是取消对其进行异步操作的唯一方法。 (EndAccept
也可以生成SocketException
,这应该正常处理。)
使用一个标记,你自己检查监听器是否仍然可用是一个麻烦,因为你引入了需要同步的共享状态(易失性读取等)。你可以通过这种方式轻松介绍种族条件。监听器已经在内部为您保留了这样一个标志,用于抛出ObjectDisposedException
,所以我只是使用它。确实,在正常情况下,捕获ObjectDisposedException
可能是编码错误的一个标志(因为你应该知道何时放置一个对象),但是使用异步代码就可以了。很标准。