【发布时间】:2014-06-21 16:16:23
【问题描述】:
我希望我不会错过一个简单的解决方案,但我已经找了好几天了。
我的 MMO 有一个客户端/服务器 Winsock MFC 架构,它在大多数情况下运行良好。
在极少数情况下,当客户端关闭连接时,服务器会收到 10053 WSAECONNABORTED 错误消息。即使从客户端的合法关闭。这是处理传入消息的服务器代码,对于未优化的代码表示歉意:
//-----------------------------------------------------------------------------
LRESULT CDXDisplay::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) //handle the messages
{
case 39245: //Network port number
{
switch (lParam) //If so, which one is it?
{
case FD_ACCEPT:
VGlobal::sSocket.AcceptSocket();
break;
case FD_CONNECT:
break;
case FD_READ:
VGlobal::sSocket.receiveSocket = wParam;
VGlobal::sSocket.ReceivePacket();
break;
case FD_WRITE:
break;
case FD_CLOSE:
VGlobal::sSocket.CloseClientConnection( wParam );
break;
}
}
break;
default:
if(message == WM_EXITSIZEMOVE || (message == WM_SIZE && (wParam == SIZE_MAXIMIZED /*|| wParam == SIZE_RESTORED*/)))
{
OnSizeScreen();
MainVant->SetDisplayMode(0);
}
return CDialog::DefWindowProc(message, wParam, lParam);
//return CWnd::DefWindowProc(message, wParam, lParam);
}
return CDialog::DefWindowProc(message, wParam, lParam);
}
程序会收到数据包,触发FD_READ,调用ReceivePacket()
//-----------------------------------------------------------------------------
int SocketServer::ReceivePacket( char * tBuffer, int tReceived )
{
ClientInfo::_packetInfo tPacket;
if( tBuffer == NULL )
{
char buffer[4096];
memset(buffer, 0, sizeof(buffer));
int received = recv( receiveSocket, buffer, sizeof(buffer) - 1, 0 );
//received = -1 and the WSAGetLastError() ID is 10053
if( received == -1 )
{
int tError = WSAGetLastError();
return 0;
}
if( received == 0 )
return 0;
//Handle packet data
_recvData tRData;
tRData.length = received;
//tRData.recvBuffer = buffer;
tRData.recvSocket = receiveSocket;
CString convStr;
LPTSTR aStr = tRData.recvBuffer.GetBufferSetLength(received);
memcpy( (void*)aStr, buffer, received );
recvDataList.push_back( tRData );
}
return 1;
}
我所做的只是忽略数据包,并等待下一个窗口消息。但是,当我这样做时,DefWindowProc() 不断地不断收到10053 错误。
我会假设阅读 MSDN 上的 recv() 函数示例和我在网络上找到的其他示例,我需要做的就是“忽略”消息并继续前进,但情况似乎并非如此。然后我只是假设我的客户端 ping 超时代码将处理客户端预错误的任何剩余数据,然后在完成后删除客户端信息。
如果有一个简单的解决方案我需要处理这个错误,我感到非常抱歉,但我似乎找不到它。
更新 1:
在进行进一步测试时,似乎在我收到进入DefWindowProc() 的不间断套接字消息然后进入recv() 函数之前,我从recv() 结果中得到不间断的10053 WSAECONNABORTED 结果,我的服务器的send() 函数也会首先触发 10053 WSAECONNABORTED。这些显然在某种程度上是相关的,但我仍然感到困惑。
那么最有可能发生的情况是,当客户端关闭时,它没有时间及时将其断开连接消息发送到服务器,因此服务器仍然在send()命令中存储数据包数据客户端的套接字并填充它,直到它最终在send() 函数上遇到10053 错误。
我不确定在此之后幕后发生了什么。但是一旦send() 函数遇到WSAECONNABORTED 错误,recv() 就会得到无穷无尽的窗口消息,同时返回WSAECONNABORTED。
现在我在这里完全猜测......但我必须假设send() 函数仍然有一个完整的数据缓冲区等待发送到已经关闭的客户端,并且网络只是不断地将数据发送到一个不存在的客户端,然后将错误发送回recv() 函数?那么我是否应该以某种方式删除send() 缓冲区中的数据,以便将其清除,然后服务器可以正常运行?
【问题讨论】:
-
39245是怎么回事?你的键盘没有配备字母吗? -
对不起,39245 只是正在使用的端口号,当收到一个数据包时,它就是它来自的端口。
-
我认为您收到
WSAECONNABORTED时需要关闭套接字。 -
您是指关闭调用
send()的服务器套接字吗?如果是这样,连接到服务器的所有其他客户端会发生什么情况?如果我关闭服务器套接字然后再次打开它,是否会重置每个人与服务器的连接?