当前位置:
首页 > temp > 简明python教程 >
-
python基础(30):黏包、socket的其他方法(3)
'))
1.2.4 黏包成因总结
黏包现象只发生在tcp协议中:
1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。
2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
1.3 黏包的解决方案
1.3.1 解决方案一
问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。
server:
- #_*_coding:utf-8_*_
- import socket,subprocess
- ip_port=('127.0.0.1',8080)
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- s.bind(ip_port)
- s.listen(5)
- while True:
- conn,addr=s.accept()
- print('客户端',addr)
- while True:
- msg=conn.recv(1024)
- if not msg:break
- res=subprocess.Popen(msg.decode('utf-8'),shell=True,\
- stdin=subprocess.PIPE,\
- stderr=subprocess.PIPE,\
- stdout=subprocess.PIPE)
- err=res.stderr.read()
- if err:
- ret=err
- else:
- ret=res.stdout.read()
- data_length=len(ret)
- conn.send(str(data_length).encode('utf-8'))
- data=conn.recv(1024).decode('utf-8')
- if data == 'recv_ready':
- conn.sendall(ret)
- conn.close()
client:
- #_*_coding:utf-8_*_
- import socket,time
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- res=s.connect_ex(('127.0.0.1',8080))
- while True:
- msg=input('>>: ').strip()
- if len(msg) == 0:continue
- if msg == 'quit':break
- s.send(msg.encode('utf-8'))
- length=int(s.recv(1024).decode('utf-8'))
- s.send('recv_ready'.encode('utf-8'))
- send_size=0
- recv_size=0
- data=b''
- while recv_size < length:
- data+=s.recv(1024)
- recv_size+=len(data)
- print(data.decode('utf-8'))
存在的问题:
程序的运行速度远快于网络传输速度,所以在发送一段字节前,先用send去发送该字节流长度,这种方式会放大网络延迟带来的性能损耗。
1.3.2 方案二
刚刚的方法,问题在于我们在发送。
我们可以借助一个模块,这个模块可以把要发送的数据长度转换成固定长度的字节。这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小,那么最终接受的数据只要达到这个值就停止,就能刚好不多不少的接收完整的数据了。
(1) struct模块
该模块可以把一个类型,如数字,转成固定长度的bytes。
- >>> struct.pack('i',1111111111111)
- struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围
- import json,struct
- #假设通过客户端上传1T:1073741824000的文件a.txt
- #为避免粘包,必须自定制报头
- header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'}
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数