Python socket连接中的粘包、精确传输问题实例分析


Posted in Python onMarch 24, 2020

本文实例讲述了Python socket连接中的粘包、精确传输问题。分享给大家供大家参考,具体如下:

粘包:

  • 发生原因:

当调用send的时候,数据并不是即时发给客户端的。而是放到了系统的socket发送缓冲区里,等缓冲区满了、或者数据等待超时了,数据才会发送,所以有时候发送太快的话,前一份数据还没有传给客户端,那么这份数据和上一份数据一起发给客户端的时候就会造成“粘包” 。

  • 解决方案:

解决根源的思想是避免不同段的数据一起发送。

    1. 方案1:前一段数据send完后,等待一段时间再send第二段数据。缺点:时间效率低,而且也无法完全避免问题【因为不清楚该设置多少时间才能保证前一份数据已经发送】
    2. 方案2:握手机制:前一段数据send完后,尝试recv,等待客户端回应,确认第一段数据发送完后,再send第二段数据。完美方案?

方案二的演示:

服务端【发送方】代码:

import socket

server=socket.socket()
server.bind(("localhost",1234))
server.listen()

while True:
  print("正在等待。。。")
  conn,addr=server.accept()
  while True:
    try:
      conn.send(b"first info")
      ack=conn.recv(1024) #接收客户端确认
      print(ack)
      conn.send(b"second info")
    except ConnectionResetError as e:
      print(e)
      break

server.close()

客户端【接收方】代码:

import socket

client=socket.socket()

client.connect(("localhost",1234))

data=client.recv(1024)
print(data.decode())
client.send(b"ack")#发送确认
data=client.recv(1024)
print(data.decode())
client.close()

不精确传输问题:

发生原因:

由于数据太大,发送方一次send不完,而接收方只recv一次,使得影响了后面数据的传输

解决方案:

解决根源的思想是改变recv的次数。

  • 方案:将数据的大小发给接收方,让接收方来决定recv的次数

方案实现代码【以解决长数据shell命令传输为例】:

服务端【发送方】:

import socket,os

server=socket.socket()
server.bind(("localhost",1234))
server.listen()
while True:
  print("正在等待...")
  conn,addr=server.accept()
  print("连接成功!")
  while True:
    try:
      cmd=conn.recv(1024)
      data=os.popen(cmd.decode()).read()
      # print(data)
      cmd_len=len(data.encode())
      print(cmd_len)
      #发现这里如果cmd_len为0会导致异常,有些是没有返回值的command
      if cmd_len==0:
        data="command has nothing return"
        cmd_len=len(data.encode())
      ##因为这里前面没有发送操作,所以不用担心粘包,如果有则要考虑处理
      conn.send(str(cmd_len).encode())#因为len结果是int,所以还要转换
      #这里要处理粘包
      ack=conn.recv(1024)
      conn.send(data.encode())
    except ConnectionResetError as e:
      print(e)
      break

server.close()

客户端【接收方】:

import socket

client=socket.socket()
client.connect(("localhost",1234))
while True:

  cmd = input(">>:")
  client.send(cmd.encode())
  data_len=client.recv(1024)
  data_len=int(data_len.decode())
  print(data_len)
  recv_len=0
  client.send(b'ack')
  total_data=b''
  while recv_len<data_len:
    data=client.recv(1024)
    recv_len+=len(data)
    total_data+=data
  print(total_data.decode())
client.close()
  • 利用这个原理可以实现文件传输,只要能确定接受次数,就能保证文件传输的大小正确。

更多关于Python相关内容可查看本站专题:《Python Socket编程技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python中利用函数装饰器实现备忘功能
Mar 30 Python
python验证码识别的实例详解
Sep 09 Python
详解Python进程间通信之命名管道
Aug 28 Python
python 读取摄像头数据并保存的实例
Aug 03 Python
Python 多线程不加锁分块读取文件的方法
Dec 11 Python
python文件写入write()的操作
May 14 Python
Python配置虚拟环境图文步骤
May 20 Python
python多线程http压力测试脚本
Jun 25 Python
Python中BeautifuSoup库的用法使用详解
Nov 15 Python
基于Python检测动态物体颜色过程解析
Dec 04 Python
浅谈pytorch、cuda、python的版本对齐问题
Jan 15 Python
Python3 多线程(连接池)操作MySQL插入数据
Jun 09 Python
Pyqt5 关于流式布局和滚动条的综合使用示例代码
Mar 24 #Python
Python+Appium实现自动化测试的使用步骤
Mar 24 #Python
Python3标准库之dbm UNIX键-值数据库问题
Mar 24 #Python
python网络编程socket实现服务端、客户端操作详解
Mar 24 #Python
python实现批量修改文件名
Mar 23 #Python
Python3 filecmp模块测试比较文件原理解析
Mar 23 #Python
python实现遍历文件夹图片并重命名
Mar 23 #Python
You might like
php密码生成类实例
2014/09/24 PHP
php使用GD库创建图片缩略图的方法
2015/06/10 PHP
浅析Yii2集成富文本编辑器redactor实例教程
2016/04/25 PHP
基于jquery的高性能td和input切换并可修改内容实现代码
2011/01/09 Javascript
使用forever管理nodejs应用教程
2014/06/03 NodeJs
JS实现点击复选框将按钮或文本框变为灰色不可用的方法
2015/08/11 Javascript
jquery动态导航插件dynamicNav用法实例分析
2015/09/06 Javascript
JavaScript控制浏览器全屏及各种浏览器全屏模式的方法、属性和事件
2015/12/20 Javascript
全面解析Bootstrap中Carousel轮播的使用方法
2016/06/13 Javascript
AngularJS实现标签页的两种方式
2016/09/05 Javascript
ionic在开发ios系统微信时键盘挡住输入框的解决方法(键盘弹出问题)
2016/09/06 Javascript
Radio 单选JS动态添加的选项onchange事件无效的解决方法
2016/12/12 Javascript
使用Vue自定义数字键盘组件(体验度极好)
2017/12/19 Javascript
使用classList来实现两个按钮样式的切换方法
2018/01/24 Javascript
ejsExcel模板在Vue.js项目中的实际运用
2018/01/27 Javascript
详解 vue better-scroll滚动插件排坑
2018/02/08 Javascript
微信小程序实现打卡日历功能
2020/09/21 Javascript
Vue项目服务器部署之子目录部署方法
2019/05/12 Javascript
JavaScript正则表达式验证登录实例
2020/03/18 Javascript
JavaScript实现网页留言板功能
2020/11/23 Javascript
[04:26]2014DOTA2西雅图国际邀请赛 总决赛TOPPLAY
2014/07/22 DOTA
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
查看django执行的sql语句及消耗时间的两种方法
2018/05/29 Python
python3基于TCP实现CS架构文件传输
2018/07/28 Python
python程序封装为win32服务的方法
2021/03/07 Python
python3+PyQt5 数据库编程--增删改实例
2019/06/17 Python
从numpy数组中取出满足条件的元素示例
2019/11/26 Python
python 实现人和电脑猜拳的示例代码
2020/03/02 Python
Python通过文本和图片生成词云图
2020/05/21 Python
PyQt5-QDateEdit的简单使用操作
2020/07/12 Python
使用Python中tkinter库简单gui界面制作及打包成exe的操作方法(二)
2020/10/12 Python
Osklen官方在线商店:巴西服装品牌
2019/04/25 全球购物
Guess欧洲官网:美国服饰品牌
2019/08/06 全球购物
辞职信模板(中英文版)
2015/02/27 职场文书
Redis中一个String类型引发的惨案
2021/07/25 Redis
JavaScript阻止事件冒泡的方法
2021/12/06 Javascript