解决WinSock中发送、接收多包问题

最近在写自己的开发库写到Socket时遇到一个很头疼的问题,那就是在发送时发送内容可能会比缓冲区大,而在接收时又不好判断什么时候接收完数据。所以写了一种发送时分割发送和分包接收后拼接的解决方案。而接收时判断数据是否传输结束,我用了select。这里以阻塞式为例子。

首先,我们需要定义一个常量,那就是我们分包时每个包的大小。如下:

#define EACH_PACK_SIZE 1024	// 单个数据包大小

在发送时,我采用了分割字符串进行分包发送的方法发送数据。

bool SendPacket(SOCKET SendSock, const char * pContent)
{
	unsigned int unPackSum = strlen(pContent) / EACH_PACK_SIZE;	// 计算分包数量
	if (strlen(pContent) % EACH_PACK_SIZE != 0)
		unPackSum += 1;

	char **szSendPack = (char **)calloc(unPackSum, sizeof(char));	// 分配内存用以存放分包内容

	for (size_t i = 0; i < unPackSum; i++)
	{
		szSendPack[i] = (char *)calloc(EACH_PACK_SIZE + 1, sizeof(char));	// 分配内存给每个分包
		strncpy_s(szSendPack[i], EACH_PACK_SIZE + 1, pContent + i * EACH_PACK_SIZE, EACH_PACK_SIZE);	// 读入分包至数组
	}

	for (size_t i = 0; i < unPackSum; i++)
	{
		ErrorCode = send(SendSock, szSendPack[i], strlen(szSendPack[i]), 0);	// 发送数据包
		if (ErrorCode == SOCKET_ERROR)	// 发送失败
		{
			closesocket(SendSock);
			return false;
		}
	}

	for (size_t i = 0; i < unPackSum; i++)	// 释放内存
		free(szSendPack[i]);

	return true;
}

而对于接收数据,由于接收数据长度不定,因此用char二维数组是不方便的,因此我选择了vector来做容器。因此,在使用前应当引用:

#include<vector>
using namespace std;

引用后,我们就可以这样处理接收数据了。

char * RecvPacket(SOCKET RecvSock)
{
	vector<char *> vecRecvPack;	// 存放接收分包
	bool bEmptyPack = false;
	fd_set crfd;
	timeval td = { 5, 0 };

	while (true)
	{
		FD_ZERO(&crfd);
		FD_SET(RecvSock, &crfd);
		select(0, &crfd, NULL, NULL, &td);

		if (FD_ISSET(RecvSock, &crfd))
		{
			bEmptyPack = false;
			char *szRecvTmp = (char *)calloc(EACH_PACK_SIZE + 1, sizeof(char));	// 分配内存用以缓冲分包
			ErrorCode = recv(RecvSock, szRecvTmp, EACH_PACK_SIZE, 0);
			vecRecvPack.push_back(szRecvTmp);	// 放入分包至数组

			FD_ZERO(&crfd);
			td = { 0, 0 };
			FD_SET(RecvSock, &crfd);
			select(0, &crfd, NULL, NULL, &td);
			if (FD_ISSET(RecvSock, &crfd))
				continue;
			else
				break;
		}
		else
		{
			bEmptyPack = true;
		}
	}

	if (bEmptyPack){
		//空数据包丢弃连接
		return char();
	}

	char *szRecvPack = (char *)calloc(EACH_PACK_SIZE * vecRecvPack.size() + 1, sizeof(char));	// 合成分包
	for (size_t i = 0; i < vecRecvPack.size(); i++)
	{
		strncpy_s(szRecvPack + (i * EACH_PACK_SIZE), EACH_PACK_SIZE + 1, vecRecvPack[i], EACH_PACK_SIZE);	// 读入分包内容至字符串
	}

	return szRecvPack;
}

至此,分包发送和接收就完成了。

时间: 2024-10-05 08:20:08

解决WinSock中发送、接收多包问题的相关文章

解决myeclipse中struts2 bug问题包的替换问题

因为struts2的bug问题,手工替换还是比较麻烦,但即便是最新的myeclipse2014也没有替换最新的struts2包,研究了一天,终于找到了解决办法.以下就解决方法与大家分享一下. 1.在perferences中找到 Myeclipse->Project Libraries,右边找到 struts2.1 Libraries,点击 Enable advanced configiguration,去掉以下文件前面的对勾,然后点击 Add custom Jars 2.在弹出的对话框中选择 A

解决Eclips中使用V7兼容包的主题报错的问题

新建项目默认会使用v7包中的主题,如果你workplace中没有v7库,那是一定会报错的. 1.导入v7jar,没用,因为需要的是v7的资源文件 2.既然如此,导入v7的整个项目应该ok了吧,import之后,尼玛还报错,百思不得骑姐,删了导,导了删,把SDK都弄坏了还是报错.并且build path还不报错. 终极大招,原来原因是因为v7库和项目没有在一个盘符下,import的时候,注意要勾选copy projects into workplace,也就是把依赖库从sdk复制一份到当前的wor

Spring使用MappingJackson2MessageConverter发送接收ActiveMQ消息

一.Spring使用JmsTemplate简化对JMS的访问 在JAVA对JMS队列访问中,使用默认的JMS支持将存在大量的检查型异常.通过Spring的支持,可以将所有的JMS的检查型异常转换为运行时非检查异常.以及在Spring中,通过配置JMSConnectionFactory的DefaultDestinationName指定发送和接收目的地. 下面是ActiveMQ的连接factory配置: 1 @Bean 2 public ActiveMQConnectionFactory getAM

【转载】串口中怎样接收一个完整数据包的解析

这里以串口作为传输媒介,介绍下怎样来发送接收一个完整的数据包.过程涉及到封包与解包.设计一个良好的包传输机制很有利于数据传输的稳定性以及正确性.串口只是一种传输媒介,这种包机制同时也可以用于SPI,I2C的总线下的数据传输.在单片机通信系统(多机通信以及PC与单片机通信)中,是很常见的问题. 一.根据帧头帧尾或者帧长检测一个数据帧 1.帧头+数据+校验+帧尾 这是一个典型的方案,但是对帧头与帧尾在设计的时候都要注意,也就是说帧头.帧尾不能在所传输的数据域中出现,一旦出现可能就被误判.如果用中断来

发送和接收数据包

发送和接收数据包 原文:Game Networking系列,作者是Glenn Fiedler,专注于游戏网络编程相关工作多年. 概述 在之前的网游中的网络编程系列1:UDP vs. TCP中(推荐先看前面那篇),我们经过讨论得出:网游中传输数据应该使用UDP而不是TCP.我们选择UDP是为了不需要等待重发数据包,从而达到数据的实时性. 注意,因为接下来英文原文中所有的代码是C++写的,而我是个pythoner,我的计划是:通过理解文章,我用python实现UDP收发数据包.虚拟连接(原文后两章的

文件的自定义包发送接收

需求 对一个特定的文件进行分片发送,构造数据包,发送数据包,接收数据包并提取有效数据,对数据组合还原为原文件. 设计 当前,基于socket的网络编程已成为当今不可替代的编程方法,它将网络通讯当作文件描述符进行处理,把对这个"网络文件"(即socket套接字)的操作抽象成一种类似于文件操作的方式进行.从实现细节上,这种工作方式根据TCP/IP的网络通讯模型,封装了一系列的实现,使得我们只需要使用一个指定的参数,就可以实现在基于所需协议的数据的发送和接收. 但是,如果我们对那些系统自动给

关于STM32-CubeMx工程中串口无法正常发送/接收的问题解决

最近翻船了,万万在第一时间没想到串口无法正常发送数据竟然是因为CubeMX软件设置的问题. 在最近一个项目中由于物料不足,导致一批板子使用了24Mhz和8Mh两种参数的晶振,写程序时也没多想,调试阶段使用的是焊接24Mhz晶振的板子,一切功能OK,可是在将时钟配置24修改未8之后,在8Mhz的板子上竟然出现了BUG,串口无法正常发送/接收数据,首先想到的是波特率,其实也就是时钟,可是没想到竟然是使用CubeMx建立工程的问题,最后还是拿出了之前建立的8MHz的模板来解决的问题. 由于时间问题,尚

共享库方案解决WAS中JAR包冲突

(一)证书导入解决方案 1.登录管理控制台. 2. 展开"安全性"并单击"SSL 证书和密钥管理".在"配置设置"下面,单击"管理端点安全配置". 3. 为 (cell):server5Cell01 管理作用域选择适当的出站配置. 4. 在"相关项目"下面,单击"密钥库和证书",然后单击 CellDefaultTrustStore 密钥库. 5.  在"其他属性"下面

NET中解决KafKa多线程发送多主题的问题

一般在KafKa消费程序中消费可以设置多个主题,那在同一程序中需要向KafKa发送不同主题的消息,如异常需要发到异常主题,正常的发送到正常的主题,这时候就需要实例化多个主题,然后逐个发送. 在NET中用RdKafka组件来做消息处理,在Nuget中引用. 在程序中初始化Producer,并创建多个Topic private string comtopic = "topic1"; private string errtopic = "topic2"; private