1.粘包概念及产生原因

1.1粘包概念:

  • TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
  • 粘包可能由发送方造成,也可能由接收方造成。
  • 只有TCP有粘包现象,UDP永远不会粘包
  • 粘包不一定会发生

1.2粘包原因:

所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

  • 发送端原因: 由于TCP协议本身的机制(面向连接的可靠地协议-三次握手机制)客户端与服务器会维持一个连接(Channel),数据在连接不断开的情况下,可以持续不断地将多个数据包发往服务器,但是如果发送的网络数据包太小,那么他本身会启用Nagle算法(可配置是否启用)对较小的数据包进行合并(基于此,TCP的网络延迟要UDP的高些)然后再发送(超时或者包大小足够)。那么这样的话,服务器在接收到消息(数据流)的时候就无法区分哪些数据包是客户端自己分开发送的,这样产生了粘包.
  • 接收端原因: 服务器在接收到数据库后,放到缓冲区中,如果消息没有被及时从缓存区取走,下次在取数据的时候可能就会出现一次取出多个数据包的情况,造成粘包现象。

2. tcp粘包解决办法

  • 在每次使用tcp协议发送数据流时,在开头标记一个数据流长度信息,并固定该报文长度(自定义协议).在客户端接收数据时先接收该长度字节数据,判断客户端发送数据流长度,并只接收该长度字节数据,就可以实现拆包,完美解决tcp粘包问题.
#struct模块介绍
#该模块可以把一个类型,如数字,转成固定长度为4的bytes类型
import struct
res = struct.pack('i',12345) #i表示整数int
print(res,len(res),type(res)) #长度是4 res2 = struct.pack('i',12345111)
print(res,len(res),type(res2)) #长度也是4 unpack_res =struct.unpack('i',res2)
print(unpack_res) #(12345111,)
print(unpack_res[0]) #12345111
###################客户端client###################
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import struct
sock=socket.socket()
sock.connect(('127.0.0.1', 13459)) content1='我好'.encode('utf-8') #要发送消息
content2='他也好'.encode('utf-8') con1_len=struct.pack('i',len(content1)) # 计算要发送消息(字节)的长度,并使用struct模块转化为长度为4的字节b'\x06\x00\x00\x00'
sock.send(con1_len) #先把这个4字节的报文发送
sock.send(content1) #发送内容 con2_len=struct.pack('i',len(content2))
sock.send(con2_len)
sock.send(content2) sock.close()
###################服务端server###################
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import struct
import socket sock = socket.socket() #买手机
sock.bind(('127.0.0.1', 13459)) #插卡
sock.listen(10) #开机(同时最大连接10) conn, addr = sock.accept() #(受)与cilent端connect(攻)对应.
msg = conn.recv(4) #首先接收4个字节(4个字节由client端struct模块转化)
len_msg= struct.unpack('i',msg) #struct模块读取报文,判断跟随数据长度.返回值是一个元祖(6,)
size_msg=len_msg[0] #取值判断跟随数据长度
msg = conn.recv(size_msg) #接收报文读取长度字节
print(msg.decode('utf-8')) #解码输出 msg=conn.recv(4)
len_msg=struct.unpack('i',msg)
size_msg=len_msg[0]
msg = conn.recv(size_msg)
print(msg.decode('utf-8')) conn.close()
sock.close()

!struct模块转化与读取都是对字节进行操作!

最新文章

  1. PHP Strict Standards:问题解决
  2. OpenCV2:Mat属性type,depth,step
  3. [转]十步完全理解SQL
  4. HDU5727 Necklace(枚举 + 二分图最大匹配)
  5. hibernate jpa 注解 @Temporal(TemporalType.DATE) 格式化时间日期,页面直接得到格式化类型的值
  6. js中prototype用法(转)
  7. 轻松理解python中的闭包和装饰器(上)
  8. IOS的UITableView
  9. (4程序框架)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  10. python socket连接服务器获取回显
  11. CPLD/FPGA厂商概述 .
  12. Scrapy定时执行爬取任务与定时关闭任务
  13. Erlang的常驻模块与功能模块
  14. 获取当前最顶层的ViewController
  15. 步步为营-55-js练习
  16. FXAA,FSAA与MSAA有什么区别?效果和性能上哪个好
  17. 【51nod】1149 Pi的递推式
  18. 原创+转发:微信小程序navigator、redirectTo、switchTab几种页面跳转方式
  19. PowerDesigner如何将消失的工具栏显示出来
  20. 启动hive命令时指定参数或自定义参数

热门文章

  1. 由浅入深--MyBatis整体架构
  2. WeifenLuo.WinFormsUI.Docking 简单入门
  3. shell中echo基础及高级用法详解-渐入佳境
  4. Netty与Spring Boot的整合
  5. openpyxl模块的读写使用及mongodb概念
  6. SQL从零到迅速精通【实用函数(3)】
  7. redirect route 路由传参
  8. 通过IMM With Remote Console为服务器安装操作系统
  9. 手写 Vue2 系列 之 patch —— diff
  10. git同步代码到另一分支