对于阻塞SOCKET来说,我们可以利用一个循环来接收包头长度的数据,然后解析出代表包体长度的那个变量,再用一个循环来接收包体长度的数据.
相关代码如下:
char PackageHead[1024]; char PackageContext[1024*20]; int len; PACKAGE_HEAD *pPackageHead; while( m_bClose == false ) { memset(PackageHead,0,sizeof(PACKAGE_HEAD)); len = m_TcpSock.ReceiveSize((char*)PackageHead,sizeof(PACKAGE_HEAD)); if( len == SOCKET_ERROR ) { break; } if(len == 0) { break; } pPackageHead = (PACKAGE_HEAD *)PackageHead; memset(PackageContext,0,sizeof(PackageContext)); if(pPackageHead->nDataLen>0) { len = m_TcpSock.ReceiveSize((char*)PackageContext,pPackageHead->nDataLen); } }m_TcpSock是一个封装了SOCKET的类的变量,其中的ReceiveSize用于接收一定长度的数据,直到接收了一定长度的数据或者网络出错才
int winSocket::ReceiveSize( char* strData, int iLen ) { if( strData == NULL ) return ERR_BADPARAM; char *p = strData; int len = iLen; int ret = 0; int returnlen = 0; while( len > 0) { ret = recv( m_hSocket, p+(iLen-len), iLen-returnlen, 0 ); if ( ret == SOCKET_ERROR || ret == 0 ) { return ret; } len -= ret; returnlen += ret; } return returnlen; }
enum IOType { IOInitialize, IORead, IOWrite, IOIdle }; class OVERLAPPEDPLUS { public: OVERLAPPEDm_ol; IOTypem_ioType; bool m_bIsPackageHead;//当前接收的数据是否是包头数据。 int m_count; WSABUF m_wsaBuffer; int m_RecvPos; char m_Buffer[1024*8];//此缓冲要尽可能大 OVERLAPPEDPLUS(IOType ioType) { ZeroMemory(this, sizeof(OVERLAPPEDPLUS)); m_ioType = ioType; } };
OVERLAPPEDPLUS*pOverlappedPlus = new OVERLAPPEDPLUS; pOverlappedPlus->m_wsaBuffer.buf = pOverlappedPlus->m_Buffer; pOverlappedPlus->m_wsaBuffer.len = PACKAGE_HEAD_LEN;///包头的长度 pOverlappedPlus->m_bIsPackageHead = true; pOverlappedPlus->m_RecvPos = 0; pOverlappedPlus->m_ioType = IORead; DWORD RecvBytes; DWORD Flags; Flags = 0; if (WSARecv(clientSocket, &(pOverlappedPlus->m_wsaBuffer), 1, &RecvBytes, &Flags, &pOverlappedPlus->m_ol, NULL) == SOCKET_ERROR) { if (WSAGetLastError() != ERROR_IO_PENDING) { delete pOverlappedPlus; } else { ///相关的错误处理 } } else { ///相关的错误处理 }
if( pOverlapPlus->m_ioType== IORead) { if( pOverlapPlus->m_wsaBuffer.len == dwIoSize ) { if( pOverlapPlus->m_bIsPackageHead == true )///接收到的是包头。 { PACKAGE_HEAD *pPackageHead = (PACKAGE_HEAD *)(pOverlapPlus->m_Buffer); if(pThis->IsLegalityPackageHead(pPackageHead)==false)///判断是否是合法的包 { closesocket(lpClientContext->m_Socket); continue; } pOverlapPlus->m_bIsPackageHead = false; pOverlapPlus->m_wsaBuffer.len = pPackageHead->nDataLen; pOverlapPlus->m_RecvPos += dwIoSize; pOverlapPlus->m_wsaBuffer.buf = pOverlapPlus->m_Buffer+pOverlapPlus->m_RecvPos; } else///接收到的是包体 { pOverlapPlus->m_RecvPos += dwIoSize; ///这时pOverlapPlus->m_Buffer里就存放了一个完整的数据包,长度为pOverlapPlus->m_RecvPos ///继续请求 请求下一个数据包的包头 pOverlapPlus->m_wsaBuffer.buf = pOverlapPlus->m_Buffer; memset(pOverlapPlus->m_Buffer,0,sizeof(pOverlapPlus->m_Buffer)); pOverlapPlus->m_wsaBuffer.len = PACKAGE_HEAD_LEN; pOverlapPlus->m_bIsPackageHead = true; pOverlapPlus->m_RecvPos = 0; } } else///接收的数据还不完整 { pOverlapPlus->m_wsaBuffer.len -= dwIoSize; pOverlapPlus->m_RecvPos += dwIoSize; pOverlapPlus->m_wsaBuffer.buf = pOverlapPlus->m_Buffer+pOverlapPlus->m_RecvPos; } pOverlapPlus->m_ioType = IORead; state = WSARecv(lpClientContext->m_Socket, &(pOverlapPlus->m_wsaBuffer), 1, &RecvBytes, &Flags, &pOverlapPlus->m_ol, NULL); if ( state == SOCKET_ERROR) { if(WSAGetLastError() != ERROR_IO_PENDING) { //关闭套接字 释放相应资源 continue; } } }
#include <iostream> using namespace std; typedef unsigned char BYTE; typedef unsigned long ULONG; const int STUDENT_LEN = 68; const int NAME_LEN = 24; const int ADDRESS_LEN = 32; typedef struct Student { int nSize; ULONG ulNumber; char szName[NAME_LEN]; int nAge; char szAddress[ADDRESS_LEN]; }STUDENT, *PSTUDENT; int SetStudentInfo(BYTE *&info, ULONG ulNum, const char *szName, const int nAge, const char *szAddress) { int nPos = 0; info = new BYTE[STUDENT_LEN]; memset(info, 0, STUDENT_LEN); *(int*)(info + nPos) = STUDENT_LEN; nPos += sizeof(int); *(ULONG*)(info + nPos) = ulNum; nPos += sizeof(ULONG); memcpy(info + nPos, szName, strlen(szName)); nPos += NAME_LEN; *(int*)(info + nPos) = nAge; nPos += sizeof(int); memcpy(info + nPos, szAddress, strlen(szAddress)); nPos += ADDRESS_LEN; return nPos; } void ReleaseInfo(BYTE *info) { if (info) { delete [] info; info = NULL; } } void GetStudentInfo(STUDENT &student, const BYTE *info) { int nPos = 0; student.nSize = *(int*)(info + nPos); nPos += sizeof(int); student.ulNumber = *(ULONG*)(info + nPos); nPos += sizeof(ULONG); memcpy(student.szName, info + nPos, NAME_LEN); nPos += NAME_LEN; student.nAge = *(int*)(info + nPos); nPos += sizeof(int); memcpy(student.szAddress, info + nPos, ADDRESS_LEN); nPos += ADDRESS_LEN; } int main(int argc, char *argv[]) { BYTE *info; STUDENT student; SetStudentInfo(info, 20064122, "tjw", 25, "shanghaipudong"); GetStudentInfo(student, info); cout << "size = " << student.nSize << endl; cout << "number = " << student.ulNumber << endl; cout << "name = " << student.szName << endl; cout << "age = " << student.nAge << endl; cout << "address = " << student.szAddress << endl; ReleaseInfo(info); return 0; }