黏包现象主要发生在TCP连接, 基于TCP的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看来,根本不知道该文件的字节流从何处开始,在何处结束.

两种黏包现象:

1 连续的小包可能会被优化算法给组合到一起进行发送

2 第一次如果发送的数据大小2000B接收端一次性接受大小为1024,这就导致剩下的内容会被下一次recv接收到,导致结果错乱

解决黏包现象的两种方案:

方案一:由于双方不知道对方发送数据的长度,导致接收的时候,可能接收不全,或者多接收另外一次发送的信息内容,所以在发送真实数据之前,要先发送数据的长度,接收端根据长度来接收后面的真实数据,但是双方有一个交互确认的过程

# 服务端
import socket
import subprocess
server = socket.socket()
ip_port = ('127.0.0.1',8001) server.bind(ip_port) server.listen() conn,addr = server.accept() while 1:
from_client_cmd = conn.recv(1024) print(from_client_cmd.decode('utf-8'))
#接收到客户端发送来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #正确结果的存放位置
stderr=subprocess.PIPE #错误结果的存放位置
)
#从管道里面拿出结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
std_msg = sub_obj.stdout.read() #为了解决黏包现象,我们统计了一下消息的长度,先将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实数据
std_msg_len = len(std_msg)
# std_bytes_len = bytes(str(len(std_msg)),encoding='utf-8')
#首先将数据长度的数据类型转换为bytes类型
std_bytes_len = str(len(std_msg)).encode('utf-8')
print('指令的执行结果长度>>>>',len(std_msg))
conn.send(std_bytes_len) status = conn.recv(1024)
if status.decode('utf-8') == 'ok': conn.send(std_msg)
else:
pass
# 客户端
import socket client = socket.socket()
client.connect(('127.0.0.1',8001)) while 1:
cmd = input('请输入指令:')
client.send(cmd.encode('utf-8')) server_res_len = client.recv(1024).decode('utf-8')
print('来自服务端的消息长度',server_res_len) client.send(b'ok') server_cmd_result = client.recv(int(server_res_len))
print(server_cmd_result.decode('gbk'))

方案二:

  Struct模块,

  打包:struct.pack(‘i’,长度)

  解包:struct.unpack(‘i’,字节)

# 服务端
import socket
import subprocess
import struct
server = socket.socket()
ip_port = ('127.0.0.1',8001) server.bind(ip_port) server.listen() conn,addr = server.accept() while 1:
from_client_cmd = conn.recv(1024) print(from_client_cmd.decode('utf-8'))
#接收到客户端发送来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #正确结果的存放位置
stderr=subprocess.PIPE #错误结果的存放位置
)
#从管道里面拿出结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
std_msg = sub_obj.stdout.read() #为了解决黏包现象,我们统计了一下消息的长度,先将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实数据
std_msg_len = len(std_msg) print('指令的执行结果长度>>>>',len(std_msg))
msg_lenint_struct = struct.pack('i',std_msg_len)
conn.send(msg_lenint_struct+std_msg)
# 客户端
import socket
import struct
client = socket.socket()
client.connect(('127.0.0.1',8001)) while 1:
cmd = input('请输入指令:')
#发送指令
client.send(cmd.encode('utf-8')) #接收数据长度,首先接收4个字节长度的数据,因为这个4个字节是长度
server_res_len = client.recv(4)
msg_len = struct.unpack('i',server_res_len)[0] print('来自服务端的消息长度',msg_len)
#通过解包出来的长度,来接收后面的真实数据
server_cmd_result = client.recv(msg_len)
print(server_cmd_result.decode('gbk'))

python之黏包和黏包解决方案的更多相关文章

  1. Python 黏包及黏包解决方案

    粘包现象 说粘包之前,我们先说两个内容,1.缓冲区.2.windows下cmd窗口调用系统指令 1 缓冲区(下面粘包现象的图里面还有关于缓冲区的解释) 每个 socket 被创建后,都会分配两个缓冲区 ...

  2. Python学习(六)模块 —— 包

    Python 包 包 定义 为了组织好模块,会将多个模块分为包.Python 处理包也是相当方便的.简单来说,包就是文件夹,但该文件夹下必须存在 __init__.py 文件. 常见的包结构如下:

  3. python(33)- 模块与包

    一 模块 1 什么是模块? 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 2 为何要使用模块? 如果你退出python解释器然后重新进入,那么你之前定义的函 ...

  4. python下的复杂网络编程包networkx的安装及使用

    由于py3.x与工具包的兼容问题,这里采用py2.7 1.python下的复杂网络编程包networkx的使用: http://blog.sina.com.cn/s/blog_720448d30101 ...

  5. Python标准库07 信号 (signal包,部分os包)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在了解了Linux的信号基础之后,Python标准库中的signal包就很容易学习 ...

  6. python 2 处理HTTP 请求的包

    httplib httplib: https://docs.python.org/2/library/httplib.html python 的官方文档这样说明: This module define ...

  7. python 3 处理HTTP 请求的包

    http http: https://docs.python.org/3/library/http.html http是一个包,里面含有多个模块:http.client,http.server,htt ...

  8. python爬虫(1)——urllib包

    人生苦短,我用python! 一.关于爬虫 鉴于我的windos环境使用命令行感觉非常不便,也懒得折腾虚拟机,于是我选择了一个折中的办法--Cmder.它的下载地址是:cmder.net Cmder是 ...

  9. python 子包引用父包和其他子包

    python 子包引用父包和其他子包 python引用子目录很简单, 里面放个__init__.py就可以了. 如何在子目录里面引用其他目录(父目录,爷目录和同辈分目录)呢? 例如: python有项 ...

  10. Python 的 JPype 模块调用 Jar 包

    背景与需求 最近学习并安装使用了HttpRunner框架去尝试做接口测试,并有后续在公司推广的打算. HttpRunner由Python开发,调用接口时需要依赖Python:而大多数公司的扩展工具包使 ...

随机推荐

  1. zabbix docker - 安装和初始化配置

    zabbix docker - 安装和初始化配置 安装zabbix server docker-mysql版本 zabbix server支持不同的数据库(详见zabbix的docker hub),这 ...

  2. cad2008 参照面板 在位编辑后无法使用

    有时候在位编辑之后,保存在位编辑了,可是参照面板无法动了,这个时候只要保存一下,然后ctrl+z,就可以解决了..蛮神奇的,我还没想到如何用代码去搞定它..

  3. 4.json解析

    格式 {"name":"zhangsan", "age":18, "books":[{"name": ...

  4. Java 10 实战第 1 篇:局部变量类型推断

    现在 Java 9 被遗弃了直接升级到了 Java 10,之前也发过 Java 10 新特性的文章,现在是开始实战 Java 10 的时候了. 今天要实战的是 Java 10 中最重要的特性:局部变量 ...

  5. 排序算法系列:快速排序算法JAVA版(靠谱、清晰、真实、可用、不罗嗦版)

    在网上搜索算法的博客,发现一个比较悲剧的现象非常普遍: 原理讲不清,混乱 啰嗦 图和文对不上 不可用,甚至代码还出错 为了不误人子弟耽误时间,推荐看一些靠谱的资源,如[啊哈!算法]系列: https: ...

  6. shiro测试常见错误

    org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.sh ...

  7. Fillder Script语法

    官方的Fiddler Script使用文档 http://docs.telerik.com/fiddler/KnowledgeBase/FiddlerScript/ModifyRequestOrRes ...

  8. java中的字符、字符串及数字之间的转换(转)

    一.string 和int之间的转换 1.string转换成int  :Integer.valueOf("12") 2.int转换成string : String.valueOf( ...

  9. oracle查看当前用户,数据库实例

    #sysdba用户登录[oracle@oracle ~]$ sqlplus / as sysdba #查看当前用户sql>show user; #查看当前数据库实例sql>show par ...

  10. xlwt set style making error: More than 4094 XFs (styles)

    使用Xlwt,当内容过多时,会报错:More than 4094 XFs (styles) 解决方法: wb = xlwt.Workbook(style_compression=2) 使用style_ ...