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

时间:2016-05-10 10:23:47

标签: c# sockets asynchronous

我觉得,我误解了.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;被调用的回调,由于尝试使用已经设置的套接字而崩溃。你能解释一下,这里有什么问题,以及听众和所有接受的连接的优雅关闭应该是什么样的?

1 个答案:

答案 0 :(得分:1)

不,这是正确的 - 您在Begin...操作中指定的回调将总是被调用,即使您关闭套接字(如果您关闭套接字,它将是叫,因为。你应该抓住你ObjectDisposedException上的EndAccept,然后返回而不采取进一步行动。关闭/部署套接字/侦听器是取消对其进行异步操作的唯一方法。 (EndAccept也可以生成SocketException,这应该正常处理。)

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