zoukankan      html  css  js  c++  java
  • tcp通信,解决断包、粘包的问题

    1、TCP和UDP的区别

    • TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的(数据没有界限)
    • UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。


    这样就会造成如下三种情况:

    1.接收端依次从发送端接收Msg1,Msg2;(正常)

    2.Msg1被发送端分割为多段发送给接收端(或者接收端先接收到Msg1和Msg2的部分数据,再接收到msg2剩下的数据);(断/拆包)

    3.Msg1和Msg2粘和在一起被发送端一次发送给接收端;(粘包)

    PS:因此,通常我们需要将接收的消息通过整理,然后分别合成一个我们需要的数据包,然后才将这个消息发送给接收端。

    2、解决TCP断包、粘包的的代码

    1. 协议如下

    报头

    长度

    数据段(N个字节)

    校验和

    0x55AA

    len

    命令类型(id)

    目标地址

    主机地址

    预留

    其它

    CRC

    2 个字节

    2 个字节(从报头到检验和所有长度)

    n1个字节

    n2个字节

    n3个字节

    n3个字节

    n4个字节

    1个字节(从报头到数据完的校验和)。

     2.代码如下:

    void TcpClient::rcvSlot()
    {
      static QByteArray allBa;  //用来存所有文件
      allBa.append(tcpClient->readAll());  //读取数据
      int head = allBa.indexOf(HEAD);    //报文头的位置,HEAD=0x55aa
      uint16_t length = 0;                               //报文(协议中)的长度
      QByteArray currentBa;
      bool checkResult = false;
      while (-1 != head)           //报文头检验
      {
        allBa = allBa.mid(head);      //去掉报头之前的
        memcpy(&length, allBa.data() + 2, 2);
        if (allBa.size() >= length)      //长度够,进行解析。报文长度校验
        {
          currentBa = allBa.mid(0, length); //获取当前完整包
          id = Mymethod:isCRC(currentBa);  //报文的和校验和id校验。(校验通过返回大于0,异常返回-1)
          if ( id)    //通过校验将数据发送
          {
            emit getPacketSignal(id, currentBa);
            qDebug() << "接收指令:" << currentBa.toHex().toUpper();

            allBa.remove(0,length+position);    //通过校验去掉取出的内容和报文头之前的内容
          }

          else

            allBa.remove(0,position+2);    //未通过校验则去掉报文头

        }

        else

          break;

        head = allBa.indexOf(HEAD);   //刷新报文头的位置
      }
    }

    PS:本人第一次写,若有不足之处请大家多多指出,希望能够和大家一起持续进步!

    坚持成就伟大
  • 相关阅读:
    【PAT甲级】1079 Total Sales of Supply Chain (25 分)
    CQOI2018 Day1 社交网络
    codeforces 707E Garlands (离线、二维树状数组)
    NOI2018 Day1 归程(Kruskal重构树)
    NOI2018 Day2 屠龙勇士(扩展孙子定理+multiset)
    知识点:二叉(重量)平衡树——替罪羊树
    BZOJ3065 带插入区间K小值
    知识点:斜率优化DP
    知识点:FFT详解
    博客园test(搭博客用)
  • 原文地址:https://www.cnblogs.com/xian-yongchao/p/9488847.html
Copyright © 2011-2022 走看看