vc++ Socket 通信添加数据包长度头,并实现拆包发送和接收

来源:赵克立博客 分类: C/C++ 标签:C/C++发布时间:2022-09-19 21:00:00最后更新:2022-09-20 20:49:26浏览:495
版权声明:
本文为博主原创文章,转载请声明原文链接...谢谢。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;
}



微信号:kelicom QQ群:215861553 紧急求助须知
Win32/PHP/JS/Android/Python