TCP客户端接收到的数据包的拆包和并包

通信约定:头两个字节(WORD)为数据包的大小。

下面是拆包和并包的代码:

UINT CNetBaseCompoment::RecvLoops()
{
	int curdatalen = 0; //当前数据长度,用于拆包并包。
	
	while (1)
	{
		DWORD dwValue = WaitForSingleObject(m_hEventQuit,0);
		if (dwValue == WAIT_OBJECT_0)
		{
			//收到停止的消息
			break;
		}
		//ERROR_MSG("进入RECV循环!\n");
		//经过拆包并包处理后,每次recv的时候数据的第一个字节总是在m_RecvBuffer[0]处
		int recvlen = recv(m_socket, m_RecvBuffer+curdatalen, sizeof(m_RecvBuffer)-curdatalen, 0);
		if (recvlen == 0)
		{
			ERROR_MSG("错误,与服务器的连接断开,ErrorCode : %d",WSAGetLastError());
			break;
		}
		else if (recvlen == -1)
		{
			ERROR_MSG("[%s]与服务器的通信发生错误: %d\n", DateTime().toString().c_str(),WSAGetLastError());
			break;
		}
		else
		{
			curdatalen += recvlen;
		}
		//开始拆包并包
		int packlen = *(USHORT*)m_RecvBuffer; 
		if(packlen <= 0 || packlen > MAX_LOCAL_BUFFER)
		{
			char szError[256] = {0};
			sprintf_s(szError,sizeof(szError),"[%s]与服务器的通信失去同步。最后的数据包大小=%d", DateTime().toString().c_str(),packlen);
			MessageBoxA(NULL,szError,"网络错误",MB_OK);
			break;
		}
		packlen += 2;		//数据头+实际长度

		while (curdatalen>=packlen)
		{
			OnRecv(m_RecvBuffer,packlen);
			curdatalen -= packlen; //处理完这批数据后,还剩下datalen个数据。
			ERROR_MSG("Data remian = %d",curdatalen);
			if (curdatalen)
			{
				memmove(m_RecvBuffer,m_RecvBuffer+packlen,curdatalen); //将剩余的数据往前移动datalen个字节。
				packlen = *(SHORT*)m_RecvBuffer; 
				if(packlen <= 0 || packlen > MAX_LOCAL_BUFFER)
				{
					char szError[256] = {0};
					sprintf_s(szError,sizeof(szError),"[%s]与服务器的通信失去同步。最后的数据包大小=%d", DateTime().toString().c_str(),packlen);
					MessageBoxA(NULL,szError,"网络错误",MB_OK);
					break;
				}
				packlen += 2;		//数据头+实际长度
			}
		}
	}
	m_bIsRun = FALSE;
	shutdown(m_socket,SD_RECEIVE);
	closesocket(m_socket);
	return 0;
}


你可能感兴趣的:(杂七杂八)