当我尝试使用.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将永远不会被调用,并且我将无法使用它来检测套接字何时发送正常断开连接。所以它不能被使用。
当然,...The唯一的问题是,在Socket.Net.Sockets.Socket或SocketAsyncEventArgs中没有OnRemoteClose (或等效的)事件可供我编写脚本,使我无法检测到套接字FIN或RST信号,并且使套接字保持打开的时间比预期的要长。C#可能有办法解决这个问题,但我无论如何也找不到它。以前还有没有人和这个搏斗过?
发布于 2018-05-09 07:52:43
事实证明,SocketAsyncEventArgs确实记录了任何远程套接字的正常终止,而与客户端语言无关。它不公开底层的TCP/IP事件或任何类似事件,而只是将套接字闭包演示为发送的空消息。
由于PEBKAC错误,我的代码没有接收到空的0字节消息,因此我永远不能“看到”正常的关机。
(如果将来有人遇到这个问题,问题是ProcessReceive方法应该在收到第一个信号后调用ReceiveAsync来继续循环,并且它...不是,因为与代码无关的原因。)
https://stackoverflow.com/questions/50241642
复制相似问题