Python Socket编程:解决粘包与长数据精确传输的两种方案

周末不加班
周末不加班
发布时间:2026-10-13| 4人浏览过
原创

本文深入分析Python Socket编程中常见的粘包与长数据截断问题。针对粘包,介绍了等待机制与握手确认两种方案,推荐握手机制以平衡效率与可靠性。针对长数据发送不全问题,提出先发送数据长度再循环接收的策略,并提供服务端与客户端的完整代码示例,适用于Shell命令执行及文件传输场景。

本文通过具体实例,详细解析Python Socket连接过程中遇到的粘包现象及长数据精确传输问题,旨在为开发者提供实用的解决方案与参考代码。

  • 发生原因:

当程序调用send方法时,数据并非立即通过网络发送给客户端,而是先写入操作系统的Socket发送缓冲区。只有当缓冲区填满或等待超时后,数据才会真正发出。因此,如果发送速度过快,前一份数据尚未完全传输给客户端,后续数据便可能紧随其后一起发出,从而导致“粘包”现象。

  • 解决方案:

解决粘包问题的核心思路是确保不同段的数据不会混合发送,即通过某种机制将数据流在逻辑上分隔开。

    1. 方案1:在发送前一段数据后,强制等待一段时间再发送第二段数据。该方法的缺点在于时间效率低下,且无法从根本上保证前一份数据已完全发送,因此难以完全避免粘包问题,具体等待时长也难以确定。
    2. 方案2:采用握手机制。在前一段数据发送完毕后,发送方尝试调用recv接收客户端的确认信号(ACK)。只有在收到客户端确认第一段数据已成功接收后,才发送第二段数据。这被视为一种较为完美的解决方案。

方案二的演示:

服务端【发送方】代码:


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 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。