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;
}