Python各协议下socket黏包问题原理


Posted in Python onApril 12, 2022

1.socket黏包问题原理

黏包:指数据与数据之间没有明确的分界线,导致不能正确的读取数据。

应用数据想要发送数据就必须将数据交给操作系统,而操作系统需要同时为所有的应用程序提供数据传输服务,就意味着不可能马上将应用数据发送,就需要为程序提供一个缓冲区,用于临时存放数据。

当发送数据很快,有两条数据都在缓冲区时,操作系统可能将两个数据发给接收方,数据之间没有分界线,接收方会误认为是一条数据。

2.UDP协议

UDP在收发数据时是基于数据包的,即一个包一个包的发送,包与包之间有明确的分界,到达对方缓冲区后也是独立数据包。这种方式存在的问题:

①发送数据的长度每个操作系统会有不同的限制,数据超过限制则无法发送;

②接收方接收数据时,如果应用程序提供的缓存容量小于数据包的长度,则会造成数据的丢失,而缓冲区大小不可能无限大。

这意味着UDP不会出现黏包问题,但会丢失数据,不可靠。

3.TCP协议

TCP增加了一套校验规则来保证数据的完整性,会将超过TCP包最大长度的数据拆分为多个TCP包,并在传输数据时为每一个TCP数据包指定一个顺序号,接收方在收到TCP数据包后按照顺序将数据包进行重组,重组后的数据全都是二进制数据,且每次收到的二进制数据之间没有明显的分界。基于这种工作机制,TCP在三种情况下发生黏包问题:

①当单个数据包较小时,接收方可能一次性读取了多个包的数据;

②当整体数据较大时,接收方可能一次性仅读取了一个包的一部分内容;

③另外TCP协议为提高效率,增加了一种优化机制,会将数据小且发送间隔短的数据合并发送,该机制也会导致发送方将两个数据包粘在一起发送。

也就是说,TCP传输数据是可靠的,但是会黏包。

4.发送方出现的黏包

服务器端:

from socket import *
server_socket = socket(AF_INET,SOCK_STREAM)
server_socket.bind(('',8080))
server_socket.listen(5)
 
new_socket,client_addr = server_socket.accept()
 
data1 = new_socket.recv(1024)
data2 = new_socket.recv(1024)
print("收到的第一条数据:",data1)
print("收到的第二条数据:",data2)
 
new_socket.close()
server_socket.close()

客户端:

from socket import *
 
client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(('10.175.193.126',8080))
client_socket.send('hello'.encode('utf-8'))
client_socket.send('word'.encode('utf-8'))
client_socket.close()

服务器端接收到的数据:

Python各协议下socket黏包问题原理

由于客户端两条数据发送间隔太短且数据包太小,被服务器端误认为是一条数据。

5. 接收方出现的黏包

服务器端:

from socket import *
import time
 
server_socket = socket(AF_INET,SOCK_STREAM)
server_socket.bind(('',8080))
server_socket.listen(5)
 
new_socket,client_addr = server_socket.accept()
print("连接成功!",client_addr)
 
data1 = new_socket.recv(3) #每次只接收三个字节,接收不完整
time.sleep(6)
print("收到的第一条数据:",data1)
 
data2 = new_socket.recv(10)
#接收第一次未接收的数据,若有空间,会继续接收新数据
print("收到的第二条数据:",data2)
 
new_socket.close()
server_socket.close()

客户端:

from socket import *
#通过time模块使客户端发送多个数据包时,时间间隔变长
import time
 
client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(('10.175.193.126',8080))
client_socket.send('hello'.encode('utf-8'))
time.sleep(5) #让当前线程休眠5秒
client_socket.send('word'.encode('utf-8'))
 
client_socket.close()

服务器端接收到的数据:

Python各协议下socket黏包问题原理

6.黏包的成因

①服务器端出现黏包:接收方不知道消息之间的界限,不知道一个消息要提取多少字节的数据造成的;

②客户端出现黏包:TCP在发送数据少且间隔时间短的数据包时,会将几条合并一起发送。

到此这篇关于Python数据传输黏包问题的文章就介绍到这了!

Python 相关文章推荐
Python计算程序运行时间的方法
Dec 13 Python
Python操作Word批量生成文章的方法
Jul 28 Python
Windows上使用virtualenv搭建Python+Flask开发环境
Jun 07 Python
Python爬虫爬取一个网页上的图片地址实例代码
Jan 16 Python
Python编程中flask的简介与简单使用
Dec 28 Python
Python3.7 新特性之dataclass装饰器
May 27 Python
详解Anconda环境下载python包的教程(图形界面+命令行+pycharm安装)
Nov 11 Python
python3.7中安装paddleocr及paddlepaddle包的多种方法
Nov 27 Python
Python+unittest+DDT实现数据驱动测试
Nov 30 Python
python中PyQuery库用法分享
Jan 15 Python
python中time tzset()函数实例用法
Feb 18 Python
Python可视化神器pyecharts绘制水球图
Jul 07 Python
Python爬虫网络请求之代理服务器和动态Cookies
Apr 12 #Python
分享Python异步爬取知乎热榜
尝试使用Python爬取城市租房信息
Apr 12 #Python
Python采集爬取京东商品信息和评论并存入MySQL
Apr 12 #Python
Python实现批量将文件复制到新的目录中再修改名称
Python多线程实用方法以及共享变量资源竞争问题
Apr 12 #Python
Python使用socket去实现TCP客户端和TCP服务端
Apr 12 #Python
You might like
php gd2 上传图片/文字水印/图片水印/等比例缩略图/实现代码
2010/05/15 PHP
简单的php+mysql聊天室实现方法(附源码)
2016/01/05 PHP
Laravel等框架模型关联的可用性浅析
2019/12/15 PHP
javascript小数计算出现近似值的解决办法
2010/02/06 Javascript
《JavaScript DOM 编程艺术》读书笔记之DOM基础
2015/01/09 Javascript
nodejs简单实现中英文翻译
2015/05/04 NodeJs
js倒计时抢购实例
2015/12/20 Javascript
微信小程序 刷新上拉下拉不会断详细介绍
2017/05/11 Javascript
Vue列表渲染的示例代码
2018/11/01 Javascript
bootstrap-table formatter 使用vue组件的方法
2019/05/09 Javascript
我要点爆”微信小程序云开发之项目建立与我的页面功能实现
2019/05/26 Javascript
微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)
2019/07/25 Javascript
[19:26]TNC vs EG (BO3)
2018/06/07 DOTA
[03:11]完美世界DOTA2联赛PWL DAY8集锦
2020/11/09 DOTA
详解Python中的__init__和__new__
2014/03/12 Python
在Python中处理字符串之isdigit()方法的使用
2015/05/18 Python
Python中shutil模块的常用文件操作函数用法示例
2016/07/05 Python
Python生成器定义与简单用法实例分析
2018/04/30 Python
python绘制散点图并标记序号的方法
2018/12/11 Python
Django使用Jinja2模板引擎的示例代码
2019/08/09 Python
分享PyCharm的几个使用技巧
2019/11/10 Python
Python爬虫爬取有道实现翻译功能
2020/11/27 Python
Python实例教程之检索输出月份日历表
2020/12/16 Python
thinkphp5 路由分发原理
2021/03/18 PHP
金山毒霸系列的笔试题
2013/04/13 面试题
Java程序开发中如何应用线程
2016/03/03 面试题
企业管理培训感言
2014/01/27 职场文书
工程专业求职自荐书范文
2014/02/08 职场文书
土木工程师职业规划范文
2014/03/07 职场文书
航空学院求职信
2014/06/11 职场文书
2014年机关党委工作总结
2014/12/11 职场文书
2015年工商局个人工作总结
2015/07/23 职场文书
纪律委员竞选稿
2015/11/19 职场文书
tensorflow学习笔记之tfrecord文件的生成与读取
2021/03/31 Python
python 如何用map()函数创建多线程任务
2021/04/07 Python
苹果的回收机器人可以通过拆解iPhone获取大量的金和铜并外公布了环境保护最新进展
2022/04/21 数码科技