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处理文本文件并生成指定格式的文件
Jul 31 Python
python统计文本文件内单词数量的方法
May 30 Python
Python实现模拟登录及表单提交的方法
Jul 25 Python
Flask框架的学习指南之用户登录管理
Nov 20 Python
Python函数参数操作详解
Aug 03 Python
Linux下Python安装完成后使用pip命令的详细教程
Nov 22 Python
python3+opencv3识别图片中的物体并截取的方法
Dec 05 Python
Django之无名分组和有名分组的实现
Apr 16 Python
pytorch 自定义数据集加载方法
Aug 18 Python
python2和python3实现在图片上加汉字的方法
Aug 22 Python
如何基于Python + requests实现发送HTTP请求
Jan 13 Python
浅谈Keras的Sequential与PyTorch的Sequential的区别
Jun 17 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对XML的操作详解
2013/06/07 PHP
成为好程序员必须避免的5个坏习惯
2014/07/04 PHP
PHP array_key_exists检查键名或索引是否存在于数组中的实现方法
2016/06/13 PHP
PHP文件上传操作实例详解
2016/09/27 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
禁止刷新,回退的JS
2006/11/25 Javascript
JavaScript Cookie显示用户上次访问的时间和次数
2009/12/08 Javascript
Javascript 闭包引起的IE内存泄露分析
2012/05/23 Javascript
js实现运动logo图片效果及运动元素对象sportBox使用方法
2012/12/25 Javascript
Javascript编写俄罗斯方块思路及实例
2015/07/07 Javascript
JavaScript知识点总结(五)之Javascript中两个等于号(==)和三个等于号(===)的区别
2016/05/31 Javascript
jQuery实现腾讯信用界面(自制刻度尺)样式
2017/08/15 jQuery
微信小程序实现点击文字页面跳转功能【附源码下载】
2017/12/12 Javascript
Chart.js 轻量级HTML5图表绘制工具库(知识整理)
2018/05/22 Javascript
用react-redux实现react组件之间数据共享的方法
2018/06/08 Javascript
微信小程序模板template简单用法示例
2018/12/04 Javascript
Layui事件监听的实现(表单和数据表格)
2019/10/17 Javascript
JavaScript实现拖动对话框效果的实现代码
2020/10/12 Javascript
原生JS实现音乐播放器的示例代码
2021/02/25 Javascript
Eclipse和PyDev搭建完美Python开发环境教程(Windows篇)
2016/11/16 Python
python中如何使用朴素贝叶斯算法
2017/04/06 Python
python实现单链表中删除倒数第K个节点的方法
2018/09/28 Python
python整小时 整天时间戳获取算法示例
2019/02/20 Python
python集成开发环境配置(pycharm)
2020/02/14 Python
关于tf.TFRecordReader()函数的用法解析
2020/02/17 Python
Django在Model保存前记录日志实例
2020/05/14 Python
tensorflow 20:搭网络,导出模型,运行模型的实例
2020/05/26 Python
Python中的None与 NULL(即空字符)的区别详解
2020/09/24 Python
借款协议书
2014/04/12 职场文书
媒体宣传策划方案
2014/05/25 职场文书
暑期培训班策划方案
2014/08/26 职场文书
高中课前三分钟演讲稿
2014/09/13 职场文书
群众路线批评与自我批评发言稿
2014/10/16 职场文书
2014年乡镇团委工作总结
2014/12/18 职场文书
2015年公司行政后勤工作总结
2015/05/20 职场文书
php远程请求CURL案例(爬虫、保存登录状态)
2021/04/01 PHP