Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在处理异步套接字(.Net)回调后,仍然会调用它_C#_Sockets_Asynchronous - Fatal编程技术网

C# 在处理异步套接字(.Net)回调后,仍然会调用它

C# 在处理异步套接字(.Net)回调后,仍然会调用它,c#,sockets,asynchronous,C#,Sockets,Asynchronous,我觉得我对.Net中的异步套接字有些误解。情况如下:我有1个异步套接字客户端和1个异步套接字服务器。它们的通信没有任何明显的问题,但当我关闭侦听器并断开客户端连接时,“OnConnectRequest”作为回调绑定到“BeginAccept”,仍然至少会被调用一次。“BeginReceive”、“OnConnectRequest”、“Disconnect”和“Dispose”方法包括: public void BeginReceive() { _listener.Bi

我觉得我对.Net中的异步套接字有些误解。情况如下:我有1个异步套接字客户端和1个异步套接字服务器。它们的通信没有任何明显的问题,但当我关闭侦听器并断开客户端连接时,“OnConnectRequest”作为回调绑定到“BeginAccept”,仍然至少会被调用一次。“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);
        }
    }
public void BeginReceive()
{
_Bind(_端点);
_listener.Listen(_maxConnections);
尝试
{
_beginacept(新的异步回调(OnConnectRequest),\u listener);
}
捕获(SocketException se)
{
OnListeningError(这是一个新的异常(“由于网络关闭或某些致命故障,服务器无法接受连接”,se));
}
}
连接请求上受保护的空隙(IAsyncResult ar)
{
套接字侦听器=(套接字)ar.AsyncState;
socketclient=listener.EndAccept(ar);
var remoteEndpoint=client.remoteEndpoint;
IDuplexStateObject状态=新的DuplexStateObject();
state.WorkSocket=客户端;
如果(_clients.CountNo,这是正确的——您在
Begin…
操作中指定的回调将始终被调用,即使您关闭套接字(如果您关闭套接字,它将因此被调用)。您应该捕获
ObjectDisposedException
您进入
EndAccept
后返回,无需进一步操作。关闭/处理套接字/侦听器是取消其异步操作的唯一方法。(
EndAccept
还可以生成
SocketException
,这应该正常处理。)


使用您自己维护的标志来检查侦听器是否仍然可用是自找麻烦,因为您引入了需要同步的共享状态(volatile reads等)。您可以通过这种方式轻松引入竞争条件。侦听器已经在内部为您维护了这样一个标志,它用于抛出
ObjectDisposedException
,因此我只使用它。在正常情况下捕获
ObjectDisposedException
可能是编码错误的标志(因为你应该知道对象何时被释放),但是对于异步代码来说这是非常标准的。

好的,所以关闭侦听器实际上是调用回调的原因。非常感谢!!但是除了捕获ObjectDisposedException之外,我还可以使用一些布尔变量(比如,“IsListening”),当侦听器关闭时,将其设置为false,并在回调中检查其值,对吗?或者在异步编程异常的世界中,这是一个更好的选择?我不认为这是一个好的答案,因为现在您无法判断是因为预期的优雅断开连接还是因为您实际上有另一个异常而处理对象在你的异步函数中的某个地方,你无意中使用了被处理的东西。这不能成为生产模式。我知道C++中,我会记录出未完成的异步IO OPS的数量,当断开连接时,我会调用关闭(使AsiCnSoCK调用用其对应的错误来响应)。然后等待剩余调用数达到0,然后再销毁所需的成员。@ChristopherPisz:如果您愿意,您可以在C#中使用完全相同的模式——是的,这将允许您调试对放置在您不希望其被放置的位置的对象的调用。请随意将其写下来作为答案。我没有这样做过然而,在过去十年的.NET开发中,额外的每个套接字状态管理是一件痛苦的事情,允许您更轻松地对错误代码进行故障排除的预期好处在实践中并不是我所需要的。我在这里写了一个单独的问题,更具体地说是关于如何等待联锁计数,因为很抱歉,我不知道怎么做。请参阅以下网页上的示例:为什么不使用async/await?