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采用django框架实现支付宝即时到帐接口
May 17 Python
Python正则表达式指南 推荐
Oct 09 Python
浅谈python 导入模块和解决文件句柄找不到问题
Dec 15 Python
浅谈python标准库--functools.partial
Mar 13 Python
基于django ManyToMany 使用的注意事项详解
Aug 09 Python
Python Pandas 转换unix时间戳方式
Dec 07 Python
python连接mongodb集群方法详解
Feb 13 Python
Python super()方法原理详解
Mar 31 Python
Pycharm连接gitlab实现过程图解
Sep 01 Python
python字符串拼接+和join的区别详解
Dec 03 Python
用OpenCV进行年龄和性别检测的实现示例
Jan 29 Python
Python探索生命起源 matplotlib细胞自动机动画演示
Apr 21 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实现子字符串位置相互对调互换的方法
2016/06/02 PHP
swoole和websocket简单聊天室开发
2017/11/18 PHP
PHP定义字符串的四种方式详解
2018/02/06 PHP
thinkPHP框架中执行事务的方法示例
2018/05/31 PHP
PHP设计模式之装饰器模式定义与用法简单示例
2018/08/13 PHP
PHP设计模式之简单工厂和工厂模式实例分析
2019/03/25 PHP
CI框架教程之优化验证码机制详解【验证码辅助函数】
2019/04/16 PHP
JS等比例缩小图片尺寸的实例
2013/02/27 Javascript
jquery实现excel导出的方法
2013/04/04 Javascript
JS对话框_JS模态对话框showModalDialog用法总结
2014/01/11 Javascript
JavaScript获取表单enctype属性的方法
2015/04/02 Javascript
jQuery实现淡入淡出二级下拉导航菜单的方法
2015/08/28 Javascript
web 前端常用组件之Layer弹出层组件
2016/09/22 Javascript
Angularjs实现带查找筛选功能的select下拉框示例代码
2016/10/04 Javascript
Java与JavaScript中判断两字符串是否相等的区别
2017/03/13 Javascript
详解jQuery中的isPlainObject()使用方法
2018/02/27 jQuery
15 分钟掌握vue-next响应式原理
2019/10/13 Javascript
vue-父子组件和ref实例详解
2019/11/10 Javascript
python虚拟环境 virtualenv的简单使用
2020/01/21 Javascript
python基础知识小结之集合
2015/11/25 Python
安装Python和pygame及相应的环境变量配置(图文教程)
2017/06/04 Python
对numpy.append()里的axis的用法详解
2018/06/28 Python
10个Python小技巧你值得拥有
2018/09/29 Python
Python访问MongoDB,并且转换成Dataframe的方法
2018/10/15 Python
Jupyter notebook在mac:linux上的配置和远程访问的方法
2019/01/14 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
2019/06/11 Python
Python3实现将一维数组按标准长度分隔为二维数组
2019/11/29 Python
Python通过zookeeper实现分布式服务代码解析
2020/07/22 Python
html5中的一些标签学习(心得)
2016/10/18 HTML / CSS
美国在线乐器和设备商店:Musician’s Friend
2018/07/06 全球购物
新加坡网上美容店:Hermo新加坡
2019/06/19 全球购物
linux系统都有哪些运行级别
2012/04/15 面试题
家居饰品店创业计划书
2014/01/31 职场文书
政府班子四风问题整改措施思想汇报
2014/10/08 职场文书
2015年新农合工作总结
2015/03/30 职场文书
2016年村党支部公开承诺书
2016/03/24 职场文书