vc++ Socket 通信添加数据包长度头,并实现拆包发送和接收
版权声明:
本文为博主原创文章,转载请声明原文链接...谢谢。o_0。
更新时间:
2022-09-20 20:49:26
温馨提示:
学无止境,技术类文章有它的时效性,请留意文章更新时间,如发现内容有误请留言指出,防止别人"踩坑",我会及时更新文章
socket通讯时数据传送的是字节流,接收方接收时一般都是用一个固定长度的缓存区来接收数据,如果传送的数据长度不固定,那么就需要自己设计传送规则以方便接收端处理,此方式也就是自定义数据传送协议
下面介绍一种常用的传送方式,socket传送数据前在数据前追加四个字节的长度来标识传送的内容长度,这样接收端就可以动态申请对应的长度来接收数据,如下
发数据前取内容长度,然后长度值放在四个字节数据中
void int2byte(byte* bytes, const unsigned int& len) { bytes[0] = (byte)len; //通过debug可以看到arr[0] = -23,也就是10010111 bytes[1] = (byte)(len >> 8); //通过debug可以看到arr[1] = -18,也就是10010010 bytes[2] = (byte)(len >> 16); //通过debug可以看到arr[2] = 51, 也就是00110011 bytes[3] = (byte)(len >> 24); //通过debug可以看到arr[3] = 1, 也就是00000001 }
接收数据前先接收四个字节然后转换成数据长度
void byte2int(const byte* bytes, unsigned int& len) { len = 0; len = len | (bytes[3] << 24); len = len | (bytes[2] << 16); len = len | (bytes[1] << 8); len = len | (bytes[0] << 0); }
定义一个常量每次包装socket数据包的最大值,Socket默认缓存大小为8K
#define SOCKET_BUFF_SIZE 1024
发数据前对数据进行包装,如果大于定义的大小则会分批发送
// 包装socket发送数据 int SendData(SOCKET socket, const std::string& str) { int len = str.length(); //申请发送数组,+4是要发送长度所占的字节数 char sendBuff[SOCKET_BUFF_SIZE + 4] = { 0 }; //长度数组并初始化 byte lenBuff[4] = { 0 }; int2byte(lenBuff, len); const unsigned int dataLen = len + 4; if (len <= SOCKET_BUFF_SIZE) { memcpy(sendBuff, lenBuff, 4); memcpy(sendBuff + 4, str.c_str(), len); return send(socket, sendBuff, dataLen, 0); } //int ret = send(socket, sendBuff, 1024 + 4, 0); int sendLenOk = 0; int ret = 0; const char* chr = str.c_str(); while (sendLenOk != len) { const int sendLenRemain = len - sendLenOk; int sendLen; if (sendLenRemain > SOCKET_BUFF_SIZE) { sendLen = SOCKET_BUFF_SIZE; } else { sendLen = sendLenRemain; } if (sendLenOk == 0) { memcpy(sendBuff, lenBuff, 4); memcpy(sendBuff + 4, chr, sendLen); sendLen += 4; } else { memcpy(sendBuff, chr + sendLenOk, sendLen); } ret = send(socket, sendBuff, sendLen, 0); if (SOCKET_ERROR == ret) { return ret; } if (sendLenOk == 0) { sendLenOk += ret - 4; } else { sendLenOk += ret; } ZeroMemory(sendBuff, SOCKET_BUFF_SIZE + 4); } return ret; }
接收数据先取长度,然后按长度取真实内容,一直取到指定的内容长度
std::string recvData(SOCKET socket) { std::string recStr; constexpr byte lenBuff[4] = { 0 }; int ret = recv(socket, (char*)lenBuff, 4, 0); unsigned int size = 0; byte2int(lenBuff, size); if (size == 0) { return recStr; } char buff_2[SOCKET_BUFF_SIZE + 1] = { 0 }; //int recLen = 0; while (size > 0) { if (size <= SOCKET_BUFF_SIZE) { ret = recv(socket, buff_2, size, 0); if (SOCKET_ERROR == ret) { break; } size -= ret; recStr += buff_2; break; } ret = recv(socket, buff_2, SOCKET_BUFF_SIZE, 0); if (SOCKET_ERROR == ret) { break; } size -= ret; recStr += buff_2; ZeroMemory(buff_2, SOCKET_BUFF_SIZE + 1); } //recStr = buff_2; //delete[] buff_2; return recStr; }