流协议与粘包,粘包差生的原因,粘包处理方案,4.readn/writen 的封装

来源:互联网 发布:武汉群光mac专柜在哪里 编辑:程序博客网 时间:2024/06/11 07:36
1. 流协议与粘包
  TCP是基于字节流的传输服务,这意味着TCP传送的数据之间是没有边界的。
  UDP是基于消息的传输服务,它传输的是报文(数据报),是具有边界的。
  字节流传输时不能保证对方接受到的是一个消息还是多个消息,所以会产生粘包问题
  基于消息传输的协议来说,能够保证对等方一次读操作只能返回一条消息。
   
2.粘包差生的原因
   a.应用层的缓冲区大小超过套接口发送缓冲区大小(消息被分割)
   b.TCP传输受最大段MSS限制
   c.链路层传输的数据受最大传输单元MTU的限制
   d.流量控制,拥塞控制,延迟发送等机制
 
3.粘包处理方案
  本质上在应用层自己维护消息与消息的边界
  a.定长报(以定长的形式发送,对等方也以定长的形式接受)
  b.包尾部加\r\n(ftp协议就用到这种方式,如果消息中本来含有\r\n 可能用到转义方式解决)
  c.包头加上包体的长度
  d.可以设计更复杂的应用层协议
 
   
4.readn/writen 的封装   
  接受/发送确切数据的操作
  方法一:定长报文(在没有接受或者发送到指定长度的报文一直接受或者发送)

       缺点:增加网络的负担假如固定长度为1024,实际有效的数据只有5个字符

//要接受确定的count字节数ssize_t readn(int fd,void *buf,size_t count) //size_t是无符号的整数ssize_t是有符号的整数{     size_t nleft =count ;//剩余的字节数    size_t nread;        //已经接受的字节数    char *bufp =(char *)buf;    while(nleft > 0)    {        if(nread =read(fd,bufp,nleft)<0)        {            if(errno ==EINTR ) //全局变量errno值为EINTR 表示信号被中断了.,这种情况不认为是失败了            {                continue;            }            else            {                return -1;            }        }        else if(nread == 0) //说明对等方关闭了        {            return count - nleft ;        }        else        {            bufp  +=nread;            nleft -=nread;        }    }    return count;}ssize_t writen(int fd,const void *buf,size_t count){    size_t nleft =count ;//剩余的字节数    ssize_t nwriten;     //已发送的字节数    char *bufp =(char *)buf;    while(nleft > 0)    {        if(nwriten =read(fd,bufp,nleft)<0)        {            if(errno ==EINTR ) //全局变量errno值为EINTR 表示信号被中断了.,这种情况不认为是失败了            {                continue;            }            else            {                return -1;            }        }        else if(nwriten == 0) //说明什么都没有发送        {            continue;        }        else        {            bufp  +=nwriten;            nleft -=nwriten;        }    }    return count;}


  方法二:加上传输数据的长度
  struct packet
  {
      int len;         //报头,在接受时先接受报头,确定包体的实际大小
      char buff[1024]; //报体
  }
原创粉丝点击