【问题标题】:.Net Sockets -> throw System.InvalidOperationException.Net 套接字-> 抛出 System.InvalidOperationException
【发布时间】:2011-01-22 10:13:22
【问题描述】:

这个问题我已经有一段时间了,而且从来没有真正能够解决它。仅当我使用 SendAsync/ReceiveAsync 方法而不是 Begin/EndSend 套接字方法进行异步操作时才会出现此问题。

如果有一个相当复杂的 tcp 套接字库,并且打算用 SendAsync 替换 BeginSend 方法,但由于我遇到的问题,我总是不得不推迟它。我的套接字服务器正在处理超过 1000 个连接的客户端以超过 100mbit/秒的速度不断推送的高压力场景,我想使用 SendAsync 方法,这样我就没有 IAsyncResult 分配开销。

无论如何,只要我只是发送/接收数据,一切都会正常工作,但是在服务器尝试断开/关闭客户端的高压力情况下,我偶尔会收到以下异常:

    System.InvalidOperationException was unhandled
  Message=Cannot apply a context that has been marshaled across AppDomains, that was not acquired through a Capture operation or that has already been the argument to a Set call.
  Source=mscorlib
  StackTrace:
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
       at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
       at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
  InnerException: 

我无法在任何地方捕捉到这个异常,因为它似乎发生在 .NET 框架中,而且我对它导致我的服务器崩溃无能为力。

由于这仅在我调用关闭过程时发生,我猜它与在套接字上调用 Shutdown 有关,而它仍然有一个读/写过程未决。 但是,我也尝试延迟调用 shutdown 直到所有读/写 Send/ReceiveAsync 调用都返回并在此之后调用shutdown,但这也无济于事。

这是我尝试关闭套接字的方法:

        private void InternalDisconnect(SocketError socketError)
    {
        lock (shutdownLock)
        {
            if (isShutdown)
                return;

            isShutdown = true;
        }

        allowSend = false;
        SocketError = socketError;

        ThreadPool.QueueUserWorkItem(delegate
                                         {
                                             lock (padLock)
                                             {
                                                 try
                                                 {
                                                     if (TcpSocketStatus == TcpSocketStatus.Disconnected)
                                                         return;

                                                     TcpSocketStatus = TcpSocketStatus.Disconnecting;

                                                     if (asyncSendArgs != null)
                                                     {
                                                         asyncSendArgs.Completed -= SendCompleted;
                                                         asyncSendArgs.SetBuffer(null, 0, 0);
                                                         asyncSendArgs.Dispose();
                                                     }

                                                     if (asyncReceiveArgs != null)
                                                     {
                                                         asyncReceiveArgs.Completed -= ReceiveCompleted;
                                                         asyncReceiveArgs.SetBuffer(null, 0, 0);
                                                         asyncReceiveArgs.Dispose();
                                                     }

                                                     try
                                                     {
                                                         bufferedSender.Clear();

                                                         Socket.Shutdown(SocketShutdown.Both);

                                                         if (Socket.Connected)
                                                         {
                                                             Socket.Disconnect(true);
                                                         }
                                                     }
                                                     catch
                                                     {
                                                     }

                                                     try
                                                     {
                                                         Socket.Close();
                                                     }
                                                     catch
                                                     {
                                                     }

                                                     TcpSocketStatus = TcpSocketStatus.Disconnected;

                                                     if (socketError != SocketError.Success)
                                                     {
                                                         if (log.IsDebugEnabled)
                                                             log.Debug("SocketDisconnected\tSocketError:{0}", socketError);
                                                     }
                                                     else
                                                     {
                                                         if (log.IsDebugEnabled)
                                                             log.Debug("SocketDisconnected");
                                                     }

                                                     DisconnectTime = DateTime.UtcNow;

                                                     if (TcpSocketDisconnected != null)
                                                         TcpSocketDisconnected(this);
                                                 }
                                                 catch (Exception ex)
                                                 {
                                                     log.ErrorException("InternalDisconnect", ex);
                                                 }
                                             }
                                         });
    }

【问题讨论】:

    标签: c# sockets asynchronous tcp


    【解决方案1】:

    好的,出于某种原因,它总是有助于我提出问题,因为我倾向于总是在不久之后弄清楚事情:/

    似乎 asyncSendArgs.SetBuffer(null, 0, 0);是罪魁祸首。 即使另一段代码应该确保在调用 InternalDisconnect 之前没有未完成的异步操作,但似乎仍然存在并且在使用缓冲区时更改缓冲区肯定会导致问题。 到目前为止,我已经进行了 15 分钟的重压测试,一切似乎都很好(在我总是在一分钟内得到那个异常之前)。我会让它运行一段时间,并希望它做到了。

    【讨论】:

    • 嗨,Tom Frey,你是如何解决这个异常的?我现在面临着那个例外
    猜你喜欢
    • 2015-11-07
    • 2018-03-08
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多