1 tcp有粘包及udp无粘包

- TCP 是面向连接的,面向流的可靠协议;发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,
合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制面向流的通信是无消息保护边界的。
- UDP(用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来
记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。 注:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,
而udp是基于数据报的,即便是你输入的是空内容(直接回车),那也不是空消息,udp协议会帮你封装上消息头

2 产生原因:

1、接收端不知道消息的界限,不知道一次提取多少字节数据
2、TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,
通常TCP会根据优化算法(Nagle算法)把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据 产生粘包场景:(1)发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
(2)接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

3 解决方案

为字节流加上自定义固定长度报头,报头中包含字节流长度,然后一次send到对端,对端在接收时,先从缓存中取出定长的报头,然后再取真实数据
struct:
注:struct 模块 把一个数字类型转化为固定长度的bytes
(struct.pack)打包 (struct.unpack)解包
res=(struct.pack('i',4855524)) #b'\x04\xe6\xe4\x02' 打包
print(res)
print(struct .unpack('i',res)[0]) #解包
服务端端:
import subprocess
import socket
import struct
import json
phone= socket.socket(socket.AF_INET ,socket.SOCK_STREAM )
phone.bind(('127.0.0.1',8080))
phone.listen(5)
while True :
conn,client=phone.accept()
while True :
try:
cmd = conn.recv(1024)
if len(cmd) == 0: break
# 远程执行命令
obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, # 解码
stdout=subprocess.PIPE, # 正确信息
stderr=subprocess.PIPE # 错误信息
)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
#先制作报头
head_dic= {'filename':'a.txt',
'total_size':len(stdout)+len(stderr),
'hash':'asdf165485221'
}
head_json = json.dumps(head_dic)
head_bytes= head_json.encode('utf-8')
#1、先把报头的长度打包成四个bytes,然后发送
conn.send(struct.pack('i',len(head_bytes))) #2、发送报头
conn.send(head_bytes)
#3、发送真实数据
conn.send(stdout )
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
phone.close()

客户端:
import struct
import socket
import json
phone= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone. connect(('127.0.0.1',8080))
while True :
msg = input('<<<')
if msg == 0:continue
#phone.send(msg.encode('utf-8'))
phone.send(bytes(msg,encoding='utf-8'))
#1、先收4个字节,该4个字节包含报头的长度 解包
header_len=struct .unpack('i',phone.recv(4))[0]
#2、通过报头长度,再接受报头内容
header_bytes=phone.recv(header_len) #通过报头长度,拿到bytes内容
#从报头中解析出想要的内容
header_json=header_bytes .decode('utf-8') #报头内容解码得到字符串类型
header_dic=json .loads(header_json) #反序列化得到字典
print(header_dic)
total_size = header_dic['total_size']
#3、再收真实的数据
recv_size =0 #初始值长度
res=b'' #接收的具体值
while recv_size< total_size:
data= phone.recv(1024)
res+=data # 拼接具体的值
recv_size += len(data) #累加长度
print(res.decode('gbk')) #收到的信息用GBK解码
phone.close()
 

tcp协议下粘包问题的产生及解决方案的更多相关文章

  1. 基于tcp协议下粘包现象和解决方案,socketserver

    一.缓冲区 每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区.write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送 ...

  2. 网络编程之tcp协议以及粘包问题

    网络编程tcp协议与socket以及单例的补充 一.单例补充 实现单列的几种方式 #方式一:classmethod # class Singleton: # # __instance = None # ...

  3. 为什么 TCP 协议有粘包问题

    为什么 TCP 协议有粘包问题 这部分转载自draveness博客. TCP/IP 协议簇建立了互联网中通信协议的概念模型,该协议簇中的两个主要协议就是 TCP 和 IP 协议.TCP/ IP 协议簇 ...

  4. 基于tcp协议的粘包问题(subprocess、struct)

    要点: 报头  固定长度bytes类型 1.粘包现象 粘包就是在获取数据时,出现数据的内容不是本应该接收的数据,如:对方第一次发送hello,第二次发送world,我放接收时,应该收两次,一次是hel ...

  5. TCP协议的粘包问题(八)

    一.什么是粘包 在socket缓冲区和数据的传递过程介绍中,可以看到数据的接收和发送是无关的,read()/recv() 函数不管数据发送了多少次,都会尽可能多的接收数据.也就是说,read()/re ...

  6. TCP协议的粘包现象和解决方法

    # 粘包现象 # serverimport socket sk = socket.socket()sk.bind(('127.0.0.1', 8005))sk.listen() conn, addr ...

  7. [Swoole系列入门教程 6] TCP协议和粘包

  8. TCP通讯处理粘包详解

    TCP通讯处理粘包详解 一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据.TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的 ...

  9. Netty(三) 什么是 TCP 拆、粘包?如何解决?

    前言 记得前段时间我们生产上的一个网关出现了故障. 这个网关逻辑非常简单,就是接收客户端的请求然后解析报文最后发送短信. 但这个请求并不是常见的 HTTP ,而是利用 Netty 自定义的协议. 有个 ...

随机推荐

  1. Python推荐系统库--Surprise实战

    一.使用movieLens数据集 from surprise import KNNBasic, SVD from surprise import Dataset from surprise impor ...

  2. .netcore读取配置文件

    setting.json { "compilerOptions": { "noImplicitAny": false, "noEmitOnError& ...

  3. INFO JobScheduler: Added jobs for time 1524468752000 ms/INFO MemoryStore: Block input-0-1524469143000 stored as bytes in memory/完全分布式 ./bin/run-example streaming.NetworkWordCount localhost 9999无法正常运行

    1.完全分布式  ./bin/run-example streaming.NetworkWordCount localhost 9999无法正常运行: 1 [hadoop@slaver1 spark- ...

  4. Ansible playbook 部署Openresty

    - hosts: all tasks: - name: copy package copy: src=/usr/local/openresty-1.13.6.1.tar.gz dest=/usr/lo ...

  5. WPF多屏最大化

    如果计算机存在多个显示器,这时设置wpf窗口为最大化,窗口只能在主显示器中实现最大化,如果想要实现窗口拉伸至多屏,需要获取所有显示器分辨率之和.这时用到了System.Windows.SystemPa ...

  6. BZOJ 4282(慎二的随机数列

    题解: 网上题解还没看 我的方法是用平衡树维护一个单调栈 由于N用了一定是赚的 所以它的作用是让f[i+1]=f[i]+1 这个是可以记录的 就跟noip蚯蚓那题一样 然后插入一个值的时候查询前面的最 ...

  7. 在CentOS 7+ 安装Kubernetes入门(单Master)

    TL;DR; ***,***,***,重要的事情说三次.如果不会***,这篇文章就没有看下去的意义.作为一个技术人员如果不愿意折腾,很难有所作为.作为一个单纯的技术人员,最好把心思放在技术上,做到真正 ...

  8. jQuery插件学习之选项卡Tab

    在网站开发中经常会用到选项卡功能,为了节省一下写代码时间,封装了一下tab插件,方便调用. 来看一下效果: tab-1 tab-2 tab-3 tabs-1-panel tabs-2-panel ta ...

  9. tomcat 反代配置

    tomcat反代可以基于nginx , http进行反代 反代服务器: 有两个网口  反代服务器一般有两块网卡一块处于外网,一块处于内网用于与后端服务器通信 tomcat 节点处于内网地址 1 tom ...

  10. NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分

    原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html 题目传送门 - 洛谷P1600 题目传送门 - LOJ#2359 题目传送门 - Vij ...