tcp协议下粘包问题的产生及解决方案

1、粘包产生原因:

(1)TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法(Nagle)把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据;

(2)接收方不知道消息之间的界限,不知道一次性提取多少字节的数据;接收时有字节的限制,如果超过这个限制没有接收完的会留在

操作系统缓存,下次再执行命令获取结果时,优先收取上次命令结果残留的信息;

注:UDP是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的,不会出现粘包问题。

2、解决方案

为字节流加上自定义固定长度报头,报头中包含字节流长度,然后一次send到对端,对端在接收时,先从缓存中取出定长的报头,然后再取真实数据。

注: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 subprocessimport socketimport structimport jsonphone= 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 structimport socketimport jsonphone= 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解码#真实数据的编码是以当前所在的系统为准的,如果是windows,那么res.stdout.read()读出的就是GBK编码的,在接收端需要用GBK解码phone.close()

原文地址:https://www.cnblogs.com/quqinchao/p/9290646.html

时间: 2024-10-08 05:01:39

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

基于tcp协议下粘包现象和解决方案

一.缓冲区 每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区.write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器.一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情.TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决

python学习_day30_基于tcp协议的粘包现象

1.基于远程执行命令的程序 需用到subprocess模块 服务端: #1.执行客户端发送的指令 import socket import subprocess phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind(('127.0.0.1',8090)) phone.listen(5) while True: conn,addr=phone.accept() print('IP:%s PORT:%s' %(addr[0

tcp协议产生-粘包问题的解决方案

客户端 1 客户端 2 3 from socket import * 4 import json,struct 5 6 7 client=socket(AF_INET,SOCK_STREAM) 8 client.connect(('127.0.0.1',8080)) 9 10 11 while True: 12 cmd=input('>>>').strip() 13 if len(cmd)==0:continue 14 client.send(cmd.encode('utf8')) 15

TCP协议下的粘包问题

TCP协议下的粘包问题 粘包问题出现在TCP协议下,在UDP协议下不会出现粘包的问题. 粘包问题出现的原因: 应用层被成为应用元,操作系统被被称为系统元 合包机制:在TCP协议下有一个合包机制,当应用层传输过来数据后,如果数据较小,并且连续多次传输,此时nagle算法会对把多个数据进行 打包,统一发送给接收方, 好处是:减少了网络资源的消耗,接收方只需要给发送方回传一份回执即可,如果不进行合包操作,每发送一条数据,接收方就需要回一份回执,会大量消耗网络资源. 弊端是:由于TCP协议下字节流没有明

TCP 拆、粘包

Netty(三) 什么是 TCP 拆.粘包?如何解决? 前言 记得前段时间我们生产上的一个网关出现了故障. 这个网关逻辑非常简单,就是接收客户端的请求然后解析报文最后发送短信. 但这个请求并不是常见的 HTTP ,而是利用 Netty 自定义的协议. 有个前提是:网关是需要读取一段完整的报文才能进行后面的逻辑. 问题是有天突然发现网关解析报文出错,查看了客户端的发送日志也没发现问题,最后通过日志发现收到了许多不完整的报文,有些还多了. 于是想会不会是 TCP 拆.粘包带来的问题,最后利用 Net

有关TCP和UDP 粘包 消息保护边界

http://www.cnblogs.com/lancidie/archive/2013/10/28/3392428.html 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有一一成对的 socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一 个大的数据块,然后进行封包.这样,接收端,就难于分辨出来了,必须提供科学的拆包机

TCP网络传输“粘包”问题,经典解决(附代码)

一.前言 关于TCP网络传输粘包,网上很多人写了原理.总结起来就一句话:这里拿Server和Client长连接,Server和Client之间通过信令传输做说明: Server发送的时候按照一条条信令发送,到达操作系统网络层,首先进入缓冲池,然后TCP协议层从池子中获取数据,传输给Client.我们知道TCP的传输有几个方案,比如,滑动窗口.1比特方案.所以Client收到的数据已经不可能是一个个完整的信令的. 个人理解TCP粘包的概念:它描述了一个场景:"信令是一个个紧挨着的,好像是被粘在一起

Netty系列(四)TCP拆包和粘包

Netty系列(四)TCP拆包和粘包 一.拆包和粘包问题 (1) 一个小的Socket Buffer问题 在基于流的传输里比如 TCP/IP,接收到的数据会先被存储到一个 socket 接收缓冲里.不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列.即使你发送了 2 个独立的数据包,操作系统也不会作为 2 个消息处理而仅仅是作为一连串的字节而言.因此这是不能保证你远程写入的数据就会准确地读取.举个例子,让我们假设操作系统的 TCP/TP 协议栈已经接收了 3 个数据包: 由于基于流传输

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务端实现并发 1.将连接循环和通信循环拆分成不同的函数 2.将通信循环做成多线程 ''' # 服务端 import socket from threading import Thread ''' 服务端 要有固定的IP和PORT 24小时不间断提供服务 能够支持并发 ''' server = sock