版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38215395/article/details/79542720
TCP是一种基于字节流的传输服务,因此,TCP所传输的数据是没有边界的。这不同于UDP提供基于消息的传输服务,其传输的数据是有边界的。TCP的发送方无法保证对等方每次接收到的是一个完整的数据包。
1、TCP粘包问题产生的原因
- 应用层通过调用write()函数,将应用层缓冲区中的数据拷贝到套接字发送缓冲区中。而套接字发送缓冲区有一个SO_SNBUF的限制。若应用层缓冲区中的数据大小大于套接字发送缓冲区的大小,则数据需要进行多次发送;
- TCP所传输的报文段有MSS(最大报文段长度)的限制,若套接字发送缓冲区的大小大于MSS,也会导致消息的分割发送;
- 由于链路层具有MTU(最大传输单元)的限制,在网络层若数据超出了MTU,会进行数据分片。
2、粘包问题的解决思路
- 发送定长包,重写read和write函数,能够接收或发送固定字节长度的数据包;
- 包尾加上“\r\n”标记。FTP就是这么做的
- 在接收时,先接收4个字节的包头,里面包含了包体的长度信息。在根据此长度来接收包体数据。
重写的read函数如下
ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft=count;
ssize_t nread;
char *bufp=(char*)buf;
while(nleft>0)
{
if((nread=read(fd,bufp,nleft))<0)
{
if(errno == EINTR)
continue;
return -1;
}
else if(nread==0)
return count-nleft;
bufp += nread;
nleft -= nread;
}
return count;
}
重写的write函数如下
ssize_t writen(int fd, void *buf, size_t count)
{
size_t nleft=count;
ssize_t nwrite;
char *bufp=(char*)buf;
while(nleft>0)
{
if((nwrite=write(fd,bufp,nleft))<0)
{
if(errno == EINTR)
continue;
return -1;
}
else if(nwrite==0)
continue;
bufp += nwrite;
nleft -= nwrite;
}
return count;
}