策略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");
}
----