Я сталкиваюсь с интересным сценарием, когда пытаюсь свернуть с .Net SocketAsyncEventArgs. А именно, тот факт, что они не могут обнаружить, когда произошло изящное удаленное отключение сокета.
Немного предыстории: я обновляю устаревшее приложение из MFC в проект .NET, и мой код должен взаимодействовать со всем другим унаследованным кодом MFC. В унаследованном коде MFC бэкэнд MFC автоматически регистрируется, когда удаленное соединение изящно закрыто с помощью сигнала FIN или RST. Я наблюдал это поведение в действии, и все, с чем пользователь может или должен взаимодействовать, - это перегрузка метода OnClose, предоставляемого MFC.
Сейчас я не могу воспроизвести это в 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 и сохранение розетки дольше ожидаемого. С #, вероятно, есть способ обойти это, но я не могу найти его. Кто-нибудь еще боролся с этим раньше?