当前位置: 首页 > news >正文

Python 网络编程之粘包问题

【一】粘包问题介绍

【1】粘包和半包

在这里插入图片描述

  • 粘包:

    • 定义: 粘包指的是发送方发送的若干个小数据包接收方一次性接收形成一个大的数据包
    • 原因: 通常是因为网络底层对数据传输的优化,将多个小数据包组合成一个大的数据块一次性传输,以提高传输效率。
    • **举例:**A给B发送了两条信息,分别是”下雨天留客天留人“和”不留“,然而B一次性全部收到了”下雨天留客天留人不留“,这就可能会让B理解成留人的意思
  • 半包:

    • 定义: 半包是指接收方在一次接收中没有完全接收到一个完整的数据包,导致数据包被切割成了两部分。
    • 原因: 可能是网络传输过程中发生了拆包,或者接收缓冲区不够大,无法容纳完整的数据包。
    • **举例:**还是同样的,A给B发的一条信息”下雨天留客天留人不留“,B却收到分开的两条信息”下雨天留客天留人“和”不留“,让B理解成不留

【2】为什么会有粘包

  • 注:只有TCP协议才有粘包现象, UDP协议永远不会粘包

  • TCP协议是面向连接的,面向流的,提供高可靠性服务。

    • 客户端和服务器端都要有一个成对的socket
    • 因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
    • 这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。
  • UDP协议是无连接的,面向消息的,提供高效率服务。

    • 不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息)
    • 这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。
  • 两种情况会发生粘包

    • 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据量小会合到一起,产生粘包)
    • 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)。

【二】解决粘包问题

  • 思路:

    • 接收端不知道发送端要发送的数据大小,那么就提前告知接收端数据的大小,这样接收端就可以完整的取出所有数据
  • 还存在的问题:

    • 需要提前发送数据的大小,这个大小也是我们需要发送的数据,那么还需要这个大小的大小,这不是陷入死循环了
  • 解决办法:

    • 通过struct模块将数据的大小进行打包
    • 因为struct模块可以输出固定字节大小的字节流数据
    • 比如:所有的int的型变量,无论大小都可以转换成4个字节的数据
    • 这个大小固定,那么每次接收端只要先判断数据的大小就可以完整接收数据
  • 代码演示:接收大数据文件

# 服务端# 导入模块
import socket
import struct# 1320KB的数据内容
big_data = ("重要信息" * 110).encode("utf8")
# 计算大小
data_size = len(big_data)
# struct生成四字节流的信息
data_size_struct = struct.pack("i", data_size)# 创建socket对象
server = socket.socket()
server.bind(("localhost", 5656))
server.listen()
conn, addr = server.accept()# 先发送数据的大小
conn.send(data_size_struct)
# 发送大数据包
conn.send(big_data)# 关闭
conn.close()
server.close()
# 客户端# 导入模块
import socket
import struct# 创建socket对象
client = socket.socket()
client.connect(("localhost", 5656))# 读取文件大小
head = client.recv(4)
total = struct.unpack("i", head)[0]# 根据大小接收数据
have = 0
data = bytes()
while have < total:data += client.recv(1024)have += 1024print(data.decode("utf8"))# 关闭
client.close()

【三】练习

  • 使用所学内容完成以下要求:
    • 创建客户端和服务端
    • 服务端给客户端提供信息列表(视频资源)
    • 客户端选择对应资源
    • 服务端传输对应资源给客户端
    • 可以尝试:
      • 分别在两台电脑上创建客户端和服务端
      • 提示:关闭防火墙,查询服务端IP地址

参考代码:

  • 运行要求:需要在服务端路径视频资源文件夹server_movie下放入一些视频文件
# 服务端# 导入模块
import os
import pickle
import socket
import struct# 创建电影资源路径
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
MOVIE_DIR = os.path.join(BASE_DIR, "server_movie")
os.makedirs(MOVIE_DIR, exist_ok=True)
movie_list = os.listdir(MOVIE_DIR)
# 生成电影资源字典
movie_dict = {index: data for index, data in enumerate(movie_list, start=1)}
# 将字典转换为字节流数据
movie_pickle = pickle.dumps(movie_dict)# 开启服务端
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
server.bind(("0.0.0.0", 9696))
server.listen(5)
# 长时间没有客户端连接
server.settimeout(5)while True:# 进行时间尝试捕获try:conn, addr = server.accept()print(f"{addr}发送链接请求")# 发送定影资源信息conn.send(movie_pickle)except socket.timeout:print("长时间没有客户端连接,服务端自动关闭")breakwhile True:# 接收选择信息res = conn.recv(1024).decode("utf8")# 退出或断开连接if res == "q" or not res:print(f"客户端{addr}断开连接")conn.close()break# 获取资源路径choice_index = int(res)movie_dir = os.path.join(MOVIE_DIR, f"{movie_dict.get(choice_index)}")# 读取电影资源with open(movie_dir, "rb") as fp:movie_data = fp.read()# 计算大小并发送head = struct.pack("i", len(movie_data))conn.send(head)conn.send(movie_data)print(f"向{addr}发送{movie_dict.get(choice_index)}完成")# 一个客户端完成conn.close()
# 关闭服务端
server.close()
# 客户端# 导入模块
import os.path
import pickle
import socket
import struct# 创建保存资源路径
DB_DIR = os.path.dirname(os.path.abspath(__file__))
MOVIE_DIR = os.path.join(DB_DIR, "client_movie")
os.makedirs(MOVIE_DIR, exist_ok=True)# 开始客户端
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
client.connect(("localhost", 9696))
# 接收资源信息字典
movie_pickle = client.recv(1024)
movie_dict = pickle.loads(movie_pickle)while True:# 打印可获取的资源print("可以从服务端拿到的资源信息如下:")for key, value in movie_dict.items():print(f"编号【{key}】  资源信息:{value}")# 选择判断choice = input("根据编号进行资源选择(Q/q:退出):>>>").strip()if choice.lower() == "q":client.send(choice.encode("utf8"))breakelif choice not in [str(i) for i in range(1, len(movie_dict) + 1)]:print("输入有误,请重新检查")continue# 发送选择编号client.send(choice.encode("utf8"))# 获取资源名字movie_name = movie_dict.get(int(choice))# 获取资源大小head_pack = client.recv(4)total = struct.unpack("i", head_pack)[0]# 下载接收文件have = 0movie_data = bytes()print(f"正在下载{movie_name}")while have < total:movie_data += client.recv(1024)have += 1024# 进度条显示progress = have / totalbar_length = 30bar = '=' * int(progress * bar_length) + '-' * (bar_length - int(progress * bar_length))percentage = progress * 100print(f'\r[{bar}] {percentage:.2f}% Complete', end='', flush=True)# 保存下载的资源movie_dir = os.path.join(MOVIE_DIR, movie_name)with open(movie_dir, "wb") as fp:fp.write(movie_data)print(f"\n{movie_name} 保存成功")
# 关闭
client.close()

相关文章:

Python 网络编程之粘包问题

【一】粘包问题介绍 【1】粘包和半包 粘包&#xff1a; 定义&#xff1a; 粘包指的是发送方发送的若干个小数据包被接收方一次性接收&#xff0c;形成一个大的数据包。原因&#xff1a; 通常是因为网络底层对数据传输的优化&#xff0c;将多个小数据包组合成一个大的数据块一次…...

旧衣回收小程序搭建:降低企业成本,提高回收效率!

在人们环保意识提升下&#xff0c;旧衣回收行业受到了大众的关注&#xff0c;同时旧衣回收具有门槛低、利润大的优势。在我国&#xff0c;回收行业不仅帮助普通人就业获利&#xff0c;还对环保做出了较大贡献。因此&#xff0c;旧衣回收行业成为了当下的热门商业模式&#xff0…...

Jmeter后置处理器——JSON提取器

目录 1、简介 2、使用步骤 1&#xff09;添加线程组 2&#xff09;添加http请求 3&#xff09; 添加JSON提取器 1、简介 JSON是一种简单的数据交换格式&#xff0c;允许互联网应用程序快速传输数据。JSON提取器可以从JSON格式响应数据中提取数据、简化从JSON原始数据中提取特定…...

[SWPUCTF 2022 新生赛]奇妙的MD5

[SWPUCTF 2022 新生赛]奇妙的MD5 wp 题目页面&#xff1a; 提示&#xff1a;可曾听过ctf 中一个奇妙的字符串。 奇妙的字符串 奇妙的字符串&#xff0c;又跟 MD5 有关&#xff0c;我只知道两个&#xff1a; 一个是 MD5 加密后弱比较等于自身&#xff0c;这个字符串是 0e215…...

MHFormer 论文解读

目录​​​​​​​ Multi-Hypothesis Transformer 结果 Introduction & Related work 多假设 为什么作者提出这个模型&#xff1f; 3.Multi-Hypothesis Transformer 3.1 Preliminary 3.2 MultiHypothesis Generation 3.3 Temporal Embedding 3.4. SelfHypothesi…...

Python列表append()函数使用详解

在Python中&#xff0c;列表是一种可变序列类型&#xff0c;可以用来存储多个元素。列表的append()函数是用于在列表末尾添加新元素的内置方法。本文将详细介绍Python列表的append()函数及其使用方法。 一、append()函数的基本语法 append()函数的语法非常简单&#xff0c;只…...

第08章_面向对象编程(高级)拓展练习(关键字:static,代码块,关键字:final,抽象类和抽象方法,接口,内部类,枚举类,注解,包装类)

文章目录 第08章_面向对象编程&#xff08;高级&#xff09;拓展练习01-关键字&#xff1a;static1、银行账户类2、图形类3、数组工具类4、二分查找5、二分查找6、素数7、阅读代码&#xff0c;分析运行结果8、阅读代码&#xff0c;分析运行结果 02-代码块9、阅读代码&#xff0…...

分布式光伏运维平台在提高光伏电站发电效率解决方案

摘要&#xff1a;伴随着能源危机和环境恶化问题的日益加重&#xff0c;科技工作者进一步加大对新能源的开发和利用。太阳能光伏发电作为新型清洁能源的主力军&#xff0c;在实际生产生活中得到了广泛的应用。然而&#xff0c;光伏发电效率偏低&#xff0c;成为制约光伏发电发展…...

2024.1.14~1.20 周内刷题总结

2024.1.14~1.20 周内刷题总结 [ABC158F] Removing Robots 题解[ABC145F] Laminate 题解[ABC254G] Elevators 题解&#xff08;坑点总结&#xff09;[ARC160C] Power Up 题解[ABC203F] Weed 题解Shopping时代的眼泪 [ABC158F] Removing Robots 题解 \qquad 题面 \qquad 本题的连…...

徐州数字孪生元宇宙赋能工业智能制造,助力传统制造业数字化转型

徐州数字孪生元宇宙赋能工业智能制造&#xff0c;助力传统制造业数字化转型。在徐州市制造业企业数字化转型的过程中&#xff0c;数字孪生技术的应用已经取得了显著成效。一方面&#xff0c;企业的生产效率得到了显著提高&#xff0c;产品质量也得到了有效保障。另一方面&#…...

智云谷再获资本市场青睐,完成数千万元A+轮融资

近日&#xff0c;深圳前海智云谷科技有限公司&#xff08;以下简称“智云谷”&#xff09;完成数千万元A轮融资&#xff0c;本轮融资由青松基金独家投资&#xff0c;多维资本担任独家融资财务顾问。本轮融资资金将用于扩大新技术研发投入、智能工厂扩产、加速产品交付&#xff…...

ACM论文LaTeX模板解析(三)| 文章顶部信息(Top matter))Part 1

本文收录于专栏&#xff1a;ACM 论文 LaTeX模板解析&#xff0c;本专栏将会围绕ACM 论文 LaTeX模板解析持续更新。欢迎点赞收藏关注&#xff01; 文章目录 有许多命令可以设置文章的顶部信息或&#xff08;计算机科学术语&#xff09;元数据。它们建立了出版物名称、文章标题、…...

[GDOUCTF 2023]受不了一点

[GDOUCTF 2023]受不了一点 wp 题目代码&#xff1a; <?php error_reporting(0); header("Content-type:text/html;charsetutf-8"); if(isset($_POST[gdou])&&isset($_POST[ctf])){$b$_POST[ctf];$a$_POST[gdou];if($_POST[gdou]!$_POST[ctf] &&…...

精心挑选免费好用的api,推荐给大家

企业基本信息&#xff1a;通过公司名称/公司ID/注册号或社会统一信用代码获取企业基本信息&#xff0c;企业基本信息包括公司名称或ID、类型、成立日期、经营状态、注册资本、法人、工商注册号、统一社会信用代码、组织机构代码、纳税人识别号等字段信息。 AI绘画-Stable Diff…...

(001)window 使用 OpenObserve

文章目录 安装上传数据报错附录 安装 1.下载安装包&#xff1a; 2. window 设置环境变量&#xff1a; ZO_ETCD_COMMAND_TIMEOUT 600 ZO_ETCD_CONNECT_TIMEOUT 600 ZO_ETCD_LOCK_WAIT_TIMEOUT 600 ZO_INGEST_ALLOWED_UPTO 10000 ZO_ROOT_USER_EMAIL 422615924qq.com ZO_…...

linux发送http请求命令

一、http get请求 1、curl命令不带参 curl “http://www.baidu.com” 如果这里的URL指向的是一个文件或者一幅图都可以直接下载到本地 curl -i “http://www.baidu.com” 显示全部信息 curl -l “http://www.baidu.com” 只显示头部信息 curl -v “http://www.baidu.com”…...

JVM实战(19)——JVM调优工具概述

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…...

Windows10无法访问github

亲测有效 1、修改hosts文件 如果电脑是Windows系统&#xff1a;打开 C:\Windows\System32\drivers\etc 找到hosts文件&#xff0c;将对应的Host地址修改为&#xff1a; #github 140.82.112.4 github.com 199.232.69.194 github.global.ssl.fastly.net 如果在保存hosts时遇到…...

GIT 分支管理办法(二)

GIT 分支管理办法&#xff08;二&#xff09; 一. 大型项目分支管理中存在的痛点 大型项目中需求的上线存在很大的不确定性&#xff0c;而且往往存在多版本、多团队、多开发并行的情况。尤其是大型企业对上线分支中编号的管理十分严苛&#xff0c;严禁夹带上线。这时对于开发…...

Vue面试之Mixins

Vue面试之Mixins 定义Mixins使用Mixins全局MixinsMixins合并策略注意事项命名冲突&#xff1a;过度使用 最近在整理一些前端面试中经常被问到的问题&#xff0c;分为vue相关、react相关、js相关、react相关等等专题&#xff0c;可持续关注后续内容&#xff0c;会不断进行整理~ …...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...