Я нашел решение: чтобы закрыть соединение без потери данных, которыми не обменивались, вы должны в основном использовать опцию SO_LINGER, это очень длинная история, которую вы можете увидеть в этой статье
но странно то, что MSDN кажется очень неточным, когда дело доходит до выключения, по моему опыту, параметры LINGER не влияли на выключение, и если вы вызываете shutdown до закрытия, то последующее закрытие больше не будет блокироваться!
наконец, вот новый код
UINT CNetServer::serveClient(LPVOID p)
{
serveClientParams* params = reinterpret_cast<serveClientParams*>(p);
try
{
AfxSocketInit();
CSocket clientSocket;
clientSocket.Attach(params->ClientSocket);
struct linger linger;
linger.l_linger = 9;
linger.l_onoff = 128;
int fls = 0;
int i = clientSocket.SetSockOpt(SO_LINGER, &linger, sizeof(linger));
i = clientSocket.SetSockOpt(SO_DONTLINGER, &fls, sizeof(fls));
CSocketFile file(&clientSocket);
CArchive arIn (&file, CArchive::load);
CArchive arOut(&file, CArchive::store);
params->ServerInstance->Consumer.Consume(arIn, arOut);
arOut.Flush();
//BOOL b = clientSocket.ShutDown(SD_BOTH);
}
catch(int ex)
{
CMisc::LogWriteWarning(ex, GetLastError(), "Listen Loop Communication");
}
catch(CException* ex)
{
char buffer[1024];
ex->GetErrorMessage(buffer, sizeof(buffer));
CMisc::LogWriteError(buffer, SOCKET_COMUNICATION_FAILED);
}
catch(...)
{
CMisc::LogWriteWarning(0, GetLastError(), "abnormal communication termination.");
}
delete params;
return 0;
}