如何使用SocketAsyncEventArgs检测套接字闭包?

时间:2018-05-08 20:16:32

标签: c# .net sockets c++-cli

当我尝试使用.Net的SocketAsyncEventArgs时,我遇到了一个有趣的场景。也就是说,他们似乎无法检测到何时发生正常的远程套接字关闭。

背景知识:我正在将遗留应用程序从MFC更新为.NET项目,我的代码需要与所有其他传统MFC代码进行交互。在传统的MFC代码中,当使用FIN或RST信号正常关闭远程连接时,MFC后端会自动注册。我已经观察到这种行为,并且所有用户可以或需要与之交互都会重载MFC提供的OnClose方法。

目前我无法在C#或C ++ / CLI中复制它。我用来处理所有接收操作的SocketAsyncEventArgs如下所示:

static void AcceptHandler(System::IAsyncResult^ ar)
{
    ServerSocket ^server = (ServerSocket ^)ar->AsyncState;
    try
    {
       server->Socket = gcnew SocketMgr(server->listener->EndAcceptSocket(ar));
       //pConnectionCb a function variable I use for updating the GUI when
       //connection status changes. ReceiveDataHandler is another function
       //variable for logging purposes.
       if (server->pConnectionChangedCb)
       {
          server->pConnectionChangedCb(server->nID);
       }

       if (server->receiveDataHandler)
       {
          System::Net::Sockets::SocketAsyncEventArgs ^receiveArgs = gcnew System::Net::Sockets::SocketAsyncEventArgs();
          receiveArgs->SetBuffer(server->readbuffer, server->nOffset, server->nBytesToGet - server->nOffset);
          receiveArgs->Completed +=
              gcnew System::EventHandler<System::Net::Sockets::SocketAsyncEventArgs ^>(server, &ServerSocket::IO_Completed);
          server->Socket->ReceiveAsync(receiveArgs);
      }
   }
   catch (System::Net::Sockets::SocketException ^e)
   {
      System::Windows::Forms::MessageBox::Show("OnAccept: Could not Accept, exception" + e->ErrorCode);
      server->listener->EndAcceptSocket(ar);
   }
}
void IO_Completed(System::Object ^sender, System::Net::Sockets::SocketAsyncEventArgs ^e)
{
   if (!(e->SocketError == System::Net::Sockets::SocketError::Success))
   {
      kPrintf("Error.");
   }
   // determine which type of operation just completed and call the associated handler
   switch (e->LastOperation)
   {
   case System::Net::Sockets::SocketAsyncOperation::Receive:
      ProcessReceive(e);
      break;
   case System::Net::Sockets::SocketAsyncOperation::Send:
      ProcessSend(e);
      break;
   default:
      throw gcnew System::ArgumentException("The last operation completed on the socket was not a receive or send");
   }
};

根据我的观察,当远程套接字不再存在时,读取过程中的SocketAsyncEventArgs对象存在于尚未完成的状态,并且永远不会完成。由于无法完成,因此永远不会调用IO_Completed,并且我将无法使用它来检测套接字何时发送正常断开连接。所以它无法使用。

...当然,唯一的问题就是没有OnRemoteClose(或等效)事件让我在Socket.Net.Sockets.Socket或SocketAsyncEventArgs中划线,让我无法检测到套接字FIN或RST信号并使插座保持打开时间超过预期。 C#可能有办法绕过这个,但我不能,因为我的生活,找到它。还有其他人在此之前摔跤吗?

1 个答案:

答案 0 :(得分:0)

事实证明,无论客户端语言如何,SocketAsyncEventArgs都会记录任何远程套接字的正常终止。它不公开底层的TCP / IP事件或类似的东西,而只是将套接字闭包演示为发送的空消息。

由于PEBKAC错误,我的代码没有收到空的0字节消息,因此我永远无法看到&#39;优雅的关机。

(如果将来有人遇到这个问题,问题是ProcessReceive方法应该在收到第一个信号后调用ReceiveAsync来继续循环,而且......不是因为无关的原因代码。)