python 粘包问题及解决方法
一粘包
TCP协议是面向对象的,面向流的,提高可靠性服务。使用了优化算法,Nagle算法。将多次间隔较少且数据量小的数据,合并成一个大的数据块,然后进行封包。这样接收端就很难分辨出来。TCP协议数据是可靠的,但是会粘包。
问题的关键是另一端并不知道你要传多少字节的数据,处理办法是必须先传一个报头,告诉另一端我要发送多少,然后另一端就接收指定数量的字节,这是可以做到的。粘包问题就解决了。
借助struct模块来解决。
二 struct模块
import struct
res=struct.pack('i',111)
print(res,len(res))
res=struct.pack('i',11111111)
print(res,len(res))
输出:
b'o\x00\x00\x00' 4
b'\xc7\x8a\xa9\x00' 4
struct模块对int类型的数字进行字节化,(bytes方法是把字符串类型的字节化),一定范围内的数字字节化后的长度都是4个字节。
import struct
res=struct.pack('i',111) #'i’是表示整数格式
print(res,len(res))
ret=struct.unpack('i',res) #unpack的结果是一个元组
print(ret)
print(ret[0]) #取第一个值,便是pack的整数
输出:
b'o\x00\x00\x00' 4
(111,)
111
三 彻底解决粘包问题。
思路:
A想要给B发送一个字典,这个字典包含filename,filesize,md5等等信息,怎么发送呢
先用json把字典序列化为字符串,然后字节化。用len方法取其长度 length。这个length就是字典字符串化字节化的长度。
在用sturct模块,pack方法将上面取到的length,字节化的结果,传给B,这个结果固定长度为4。
B这边,先recv(4),拿到后,用struct的unpack方法,取到的就是字典字符串化字节化的长度length。
在recv(length),拿到的就是字典字符串化字节化的结果。这个结果怎么来的就怎么倒回去,decode,json.loads(),拿到字典。拿到filesize。
while循环,接收长度为filesize的字节。
到此,粘包问题解决,大功告成。
简言之:
服务器 1 发送报头的长度。借用struct模块 客户端 1 接收报头的长度。 recv(4),struct模块unpack取到报头的长度length
2 发送报头。借用json模块 2 接收报头。 recv(lenth)。json反序列化得到报头。报头中有‘’size‘’
3 发送真实数据 3 接收真实数据 报头中含有size,对应真实数据的数据。
客户端:
import socket
import struct
import json
#1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #2、打电话
phone.connect(('127.0.0.1',8092)) #3、发收消息
while True:
cmd=input('>>: ').strip()
if cmd == 'quit':break
if not cmd:continue
phone.send(cmd.encode('utf-8'))
#先收报头长度
obj=phone.recv(4)
header_size=struct.unpack('i',obj)[0] #再收报头
header_bytes=phone.recv(header_size)
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json)
print(header_dic)
#最后循环收真实的数据
total_size=header_dic['total_size']
filename=header_dic['filename'] total_data=b''
recv_size=0
with open(filename,'wb') as f:
while recv_size < total_size:
recv_data=phone.recv(1024)
total_data+=recv_data
recv_size+=len(recv_data)
print(total_data.decode('gbk')) #4、挂电话
phone.close()
服务端
import socket
import subprocess
import struct
import json
#1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #2、绑定手机卡
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('192.168.11.53',8080)) #3、开机
phone.listen(5) #4、等电话连接
print('starting...')
while True: #连接循环
conn,addr=phone.accept()
print('IP:%s,PORT:%s' %(addr[0],addr[1])) #5、收发消息
while True: #通信循环
try:
cmd=conn.recv(1024) #最大收1024
if not cmd:break #针对linux #执行命令
obj=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
#制作报头
header_dic = {'filename': 'a.txt',
'total_size': len(stdout)+len(stderr),
'md5': 'asdfa123xvc123'} header_json = json.dumps(header_dic) header_bytes = header_json.encode('utf-8') #先发报头的长度。发送的长度是字典格式的报头经过json化的bytes化处理的长度。经过struct.pack,固定长度为4个字节。
conn.send(struct.pack('i',len(header_bytes)))
#再发送报头。发送的报头是json化,bytes化后的报头。
conn.send(header_bytes)
#最后发送真实数据
conn.send(stdout)
conn.send(stderr)
except Exception:
break #6、挂电话
conn.close() #7、关机
phone.close()
python 粘包问题及解决方法的更多相关文章
- 网络编程——TCP协议、UDP协议、socket套接字、粘包问题以及解决方法
网络编程--TCP协议.UDP协议.socket套接字.粘包问题以及解决方法 TCP协议(流式协议) 当应用程序想通过TCP协议实现远程通信时,彼此之间必须先建立双向通信通道,基于该双向通道实现数 ...
- python粘包分析与解决
TCP与UDP协议 TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此 ...
- 网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法
TCP协议:传输协议,基于端口工作 三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立 ...
- TCP协议的粘包现象和解决方法
# 粘包现象 # serverimport socket sk = socket.socket()sk.bind(('127.0.0.1', 8005))sk.listen() conn, addr ...
- 网络编程----粘包以及粘包问题的解决、FTP上传
一.粘包现象 让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig) 注意注意: res=subprocess.Popen(cmd.decode('u ...
- 什么是TCP粘包?怎么解决这个问题
在socket网络编程中,都是端到端通信,由客户端端口+服务端端口+客户端IP+服务端IP+传输协议组成的五元组可以明确的标识一条连接.在TCP的socket编程中,发送端和接收端都有成对的socke ...
- 在国内使用maven下载jar包非常慢的解决方法
在国内使用maven下载jar包非常慢的解决方法 1.原因: 很多jar包在国外环境,所以会很慢. 2.解决方法 maven支持镜像环境下载,所以首先找到maven的conf目录中的settings. ...
- Python更新pip出现错误解决方法
Python更新pip出现错误解决方法 更新pip python -m pip install --upgrade pip 查看时报错 解决方法 在命令栏(即win+r)输入:easy_install ...
- python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色)
python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色) 前言 在 python 开发中,有时候想通过cmd窗口来和用户交互,比如显示信息之类的,会比自己创建 GUI 来的方便,但是随之而 ...
随机推荐
- python3从尾到头打印链表
题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 方法一:通过栈实现 # -*- coding:utf-8 -*- # class ListNode: # def __ini ...
- extranuclear gene|non-Mendelian inheritance|uniparental inheritance|maternal inheritance
5.8某些细胞器含有DNA 因为除细胞核内的染色体外,细胞质中的细胞器上也有遗传物质(这类遗传物质被称为核外基因(extranuclear gene),比如线粒体上的rRNA,这是因为细胞器基因组是独 ...
- HTML5 跨文档消息传输
对窗口对象的message事件进行监听 window.addEventListener("message", function(event) { // 处理程序代码 }, fals ...
- 一步一步构建iOS持续集成:Jenkins+GitLab+蒲公英+FTP
什么是持续集成 持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成.每次集成都通过自动化的构建(包括编译,发布,自动化测试)来 ...
- js中实现杨辉三角
实现效果:杨辉三角 即: 提示用户输入要实现的杨辉三角行数: 请输入杨辉三角的行数: 8 代码实现后的效果如下: 1 1.1 1.2.1 1.3.3.1 1.4.6.4.1 1.5.10.10.5.1 ...
- matlplotlib根据函数画出图形
根据函数画出函数的轨迹 import matht = np.linspace(0, math.pi, 1000)x = np.sin(t)y = np.cos(t) + np.power(x, 2.0 ...
- Voyager如何使用Compass
Compass由Resources,Commands,Logs三个部分组成 Resources包含了Links和Fonts: Commands可以执行php命令,比如创建model: 创建一个Down ...
- LeetCode之Weekly Contest 102
第一题:905. 按奇偶校验排序数组 问题: 给定一个非负整数数组 A,返回一个由 A 的所有偶数元素组成的数组,后面跟 A 的所有奇数元素. 你可以返回满足此条件的任何数组作为答案. 示例: 输入: ...
- mac Parallels Desttop 13 win7/win8 无法连接网络
把 “源” 从共享网络改为"Wi-Fi" 在mac 这边点击菜单栏windows图标,选配置(如果没有配置,点控制中心,在点控制中心的齿轮,)选 硬件 找到网络 解锁,上边第一行就 ...
- 【mac】【nginx】开机重启
homebrew.mxcl.nginx.plist <?xml version="1.0" encoding="UTF-8"?> <!DOCT ...