Linux网络编程学习笔记(6)---TCP中的粘包问题及解决方案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38215395/article/details/79542720

TCP是一种基于字节流的传输服务,因此,TCP所传输的数据是没有边界的。这不同于UDP提供基于消息的传输服务,其传输的数据是有边界的。TCP的发送方无法保证对等方每次接收到的是一个完整的数据包。

1、TCP粘包问题产生的原因

  1. 应用层通过调用write()函数,将应用层缓冲区中的数据拷贝到套接字发送缓冲区中。而套接字发送缓冲区有一个SO_SNBUF的限制。若应用层缓冲区中的数据大小大于套接字发送缓冲区的大小,则数据需要进行多次发送;
  2. TCP所传输的报文段有MSS(最大报文段长度)的限制,若套接字发送缓冲区的大小大于MSS,也会导致消息的分割发送;
  3. 由于链路层具有MTU(最大传输单元)的限制,在网络层若数据超出了MTU,会进行数据分片。

2、粘包问题的解决思路

  1. 发送定长包,重写read和write函数,能够接收或发送固定字节长度的数据包;
  2. 包尾加上“\r\n”标记。FTP就是这么做的
  3. 在接收时,先接收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;
}

猜你喜欢

转载自blog.csdn.net/weixin_38215395/article/details/79542720