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:本人第一次写,若有不足之处请大家多多指出,希望能够和大家一起持续进步!

tcp通信,解决断包、粘包的问题的更多相关文章

  1. UNIX网络编程——tcp流协议产生的粘包问题和解决方案

    我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体 ...

  2. Socket 编程中,TCP 流的结束标志与粘包问题

    因为 TCP 本身是无边界的协议,因此它并没有结束标志,也无法分包. socket和文件不一样,从文件中读,读到末尾就到达流的结尾了,所以会返回-1或null,循环结束,但是socket是连接两个主机 ...

  3. [转]java nio解决半包 粘包问题

    java nio解决半包 粘包问题 NIO socket是非阻塞的通讯模式,与IO阻塞式的通讯不同点在于NIO的数据要通过channel放到一个缓存池ByteBuffer中,然后再从这个缓存池中读出数 ...

  4. tcp流协议产生的粘包问题和解决方案

    我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体 ...

  5. C#网络编程学习(5)---Tcp连接中出现的粘包、拆包问题

    本文参考于CSDN博客wxy941011 1.疑问 我们使用第四个博客中的项目. 修改客户端为:连接成功后循环向服务器发送从1-100的数字.看看服务器会不会正常的接收100次数据. 可是我们发现服务 ...

  6. Python 32 通信循环 连接循环 粘包问题

    一:通信循环 二:连接循环 三:粘包问题

  7. Go语言网络通信---tcp上传大文件(粘包问题还需优雅解决)

    server端: package main import ( "bufio" "encoding/binary" "fmt" "n ...

  8. tcp协议传输中的粘包问题

    什么是粘包问题 tcp是流体协议. 其nagle算法会将数据量较小. 并且发送间隔时间较短的多个数据包合并为一个发送. 网络传输的时候是一段一段字节流的发送. 在接收方看来根本不知道字节流从何开始. ...

  9. netty10---分包粘包

    客户端:根据 长度+数据 方式发送 package com.server; import java.net.Socket; import java.nio.ByteBuffer; public cla ...

  10. 网络编程3 网络编程之缓冲区&subprocess&粘包&粘包解决方案

    1.sub简单使用 2.粘包现象(1) 3.粘包现象(2) 4.粘包现象解决方案 5.struct学习 6.粘包现象升级版解决方案 7.打印进度条

随机推荐

  1. js数组中对象去重 (reduce() 方法)

    一个数组中含有对象,并且去掉数组中重复的对象.主要代码如下: var arrData = [ {id: , name: "小明"}, {id: , name: "小张&q ...

  2. [转]WPF的依赖属性是怎么节约内存的

    WPF升级了CLR的属性系统,加入了依赖属性和附加属性.依赖属性的使用有很多好处,其中有两点是我认为最为亮眼的: 1)节省内存的开销; 2)属性值可以通过Binding依赖于其它对象上,这就使得我的数 ...

  3. thinkphp 替换入口

    3.2版本支持根据当前的运行环境生成Lite文件,可以替换框架的入口文件或者应用入口文件,提高运行效率. 我们的建议是在生产环境中关闭调试模式后生成Lite文件.注意,目前SAE平台不支持直接生成Li ...

  4. JQuery简单实用的模板引擎

    1.在html界面声明模板(注意type类型) <script id="tmplInvokeProvider" type="text/x-jquery-tmpl&q ...

  5. NOIp2018集训test-9-5(am)

    Problem A. maze 递归处理,题解写得真简单. 我大概这辈子也写不出来这种东西吧. Problem B. count 容易发现合法的数中一定有且仅有两个数加起来等于10,其他数两两配对加起 ...

  6. python virtual env 使用 jupyter ipython notebook,舒服了, 工作效率翻倍

    话不多说,尊重原作者 知乎链接

  7. jQuery 基本使用

    index.html <head><meta http-equiv="Content-Type" content="text/html; charset ...

  8. (转)AttributeError: module 'tkinter' has no attribute 'messagebox'

    AttributeError: module 'tkinter' has no attribute 'messagebox' improt tkinter from tkinter import * ...

  9. 剑指offer——07用两个栈实现队列

    题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型.   题解: 有两个栈,stack1和stack2 push只在stack1上操作,pop只在stack2 ...

  10. QT5+Pylon

    VS+QT+Pylon:配置一下包含文件和libs,具体参考pylon说明文档. Windows下  Qtcreator+Pylon:建议把include和libs文件夹拷贝至工作目录,然后修改.pr ...