调用此函数以在新线程中为每个客户端提供服务。在使用函数中,这些存档被读取和写入,但函数在客户端完成读取所有响应之前返回,因此套接字超出范围并关闭,在客户端中创建异常。我假设CArchive上的任何写操作都应该阻塞,直到它在客户端读取为止。我在这做错了吗? 如果我在退出范围之前添加延迟(尝试)这个代码工作正常,这不是一个好方法,我想知道有没有办法阻止所有数据传输?
由于
UINT CNetServer::serveClient(LPVOID p)
{
serveClientParams* params = reinterpret_cast<serveClientParams*>(p);
try
{
AfxSocketInit();
CSocket clientSocket;
clientSocket.Attach(params->ClientSocket);
CSocketFile file(&clientSocket);
CArchive arIn (&file, CArchive::load);
CArchive arOut(&file, CArchive::store);
params->ServerInstance->Consumer.Consume(arIn, arOut);
arOut.Flush();
file.Flush();
//SleepEx(1000,true); works fine is I wait till the data is sent.
}
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;
}
答案 0 :(得分:1)
我找到了解决方案,为了关闭连接而不丢失任何未交换的数据,你基本上应该使用SO_LINGER选项,这是一个很长的故事你可以在this article
中看到细节但奇怪的是,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;
}
答案 1 :(得分:0)
我对这个问题没有确切的想法。无论如何请尝试以下,它可以解决您的问题。
不允许销毁clientSocket
。为此,您可以动态创建它,也可以在全局范围内创建它,如下所示。
1. UINT CNetServer::serveClient(LPVOID p)
{
:
CSocket* clientSocket = new CSocket;
:
}
2. CSocket clientSocket; // Global scope
UINT CNetServer::serveClient(LPVOID p)
{
:
}