策略2种:
1. 首先,接收一个长度。然后,根据长度再继续接收数据。(感觉要好一点)
2. 直接接收所有,再判断长度
方法1 : 先收长度,再收数据(推荐)
最近在调程序的时候,发现发送端发送一个119136个char的内存的时候,在接收端不能全部接收,
于是,通过调试发现,必须在接收端多次的recv以后,进行拼接:
代码如下:
char Lenbuf[4];
方法2:一次接收,在判断长度
在每个 报头上说明包体的长度,这样通过报头大小来获取相应的数据大小;
在此主要讨论解决方法3,在报头说明包体大小的方式
在此方式中,每个包都分为两部分,第一部分为数据部分的大小,紧接的部分是数据部分,可以用结构体实现
struct packet{
unsigned int m_msgLen;
char data[maxsize];
}
这样数据在发送的过程中将报头和包体全部发送,在接收的时候先接收4字节的包头数据
int a;
recv(sockfd,&a,4,0);
或者recv(sockfd,buff,maxsize,0);//线将缓冲区数据全部拿出来再处理
strncpy(&a,buff,4);
这样就可以获取包体数据大小,然后通过报头大小获取包体数据来解决粘包
==============================================
代码:
粘包解决方案二:使用结构体,显式说明数据部分的长度
在这个方案中,我们需要定义一个‘struct packet’包结构,结构中指明数据部分的长度,用四个字节来表示。发送端的对等方接收报文时,先读取前四个字节,获取数据的长度,由长度来进行数据的读取。定义一个结构体
struct packet
{
unsigned int msgLen ; //4个字节字段,说明数据部分的大小
char data[512] ; //数据部分
}
读写过程如下所示,这里抽取关键代码进行说明:
//发送数据过程
struct packet writebuf;
memset(&writebuf,0,sizeof(writebuf));
while(fgets(writebuf.data,sizeof(writebuf.data),stdin)!=NULL)
{
int n = strlen(writebuf.data); //计算要发送的数据的字节数
writebuf.msgLen =htonl(n); //将该字节数保存在msgLen字段,注意字节序的转换
writen(conn,&writebuf,4+n); //发送数据,数据长度为4个字节的msgLen 加上data长度
memset(&writebuf,0,sizeof(writebuf));
}
下面是读取数据的过程,先读取msgLen字段,该字段指示了有效数据data的长度。依据该字段再读出data。
memset(&readbuf,0,sizeof(readbuf));
int ret = readn(conn,&readbuf.msgLen,4); //先读取四个字节,确定后续数据的长度
if(ret == -1)
{
err_exit("readn");
}
else if(ret == 0)
{
printf("peer close\n");
break;
}
int dataBytes = ntohl(readbuf.msgLen); //字节序的转换
int readBytes = readn(conn,readbuf.data,dataBytes); //读取出后续的数据
if(readBytes == 0)
{
printf("peer close\n");
break;
}
if(readBytes<0)
{
err_exit("read");
}
----
本文探讨了解决网络通信中粘包问题的两种策略。一种是先接收数据长度,再根据长度接收数据;另一种是在接收端一次性接收所有数据,再判断实际长度。通过实例代码展示了如何使用这两种方法确保数据包的完整性和准确性。
1312





