python入门开发学习笔记之粘包现象与解决方案
发布日期:2025-05-13 01:15:46 浏览次数:2 分类:精选文章

本文共 4136 字,大约阅读时间需要 13 分钟。

粘包问题是指在使用TCP协议时,客户端和服务器端可能会收到多个消息粘在一起,导致接收端无法正确识别消息的界限。这种现象常见于远程执行命令程序中,尤其是在发送大量数据或长输出时。

粘包问题的原因

  • TCP是面向流的协议:TCP不关心每个消息的大小,会将多个消息合并成一个大块发送,导致接收方难以识别消息的界限。
  • 发送方和接收方的缓冲区:数据在传输过程中会被临时存储,可能导致部分数据被拆分或延迟发送。
  • 解决粘包问题的方法

  • 发送消息长度:发送方在发送数据前发送消息的长度,接收方根据长度等待完整数据。
  • 自定义报头:在消息前添加固定长度的报头,包含消息的总大小和其他元数据,确保接收方可以准确识别消息界限。
  • 使用第三方模块:如struct模块,自定义报头和数据格式,确保数据传输的准确性和完整性。
  • 实现方法

  • 简单远程执行命令程序开发

    • 服务器端

      import socket
      import subprocess
      ip_port = ('127.0.0.1', 8080)
      tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      tcp_socket_server.bind(ip_port)
      tcp_socket_server.listen(5)
      while True:
      conn, addr = tcp_socket_server.accept()
      print('客户端', addr)
      while True:
      cmd = conn.recv(1024)
      if not cmd:
      break
      res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
      stdout=subprocess.PIPE, stdin=subprocess.PIPE,
      stderr=subprocess.PIPE)
      stderr = res.stderr.read()
      stdout = res.stdout.read()
      data_length = len(stdout + stderr)
      conn.sendall(str(data_length).encode('utf-8'))
      data = conn.recv(1024).decode('utf-8')
      if data == 'recv_ready':
      conn.sendall(stdout + stderr)
      conn.close()
    • 客户端

      import socket
      import time
      ip_port = ('127.0.0.1', 8080)
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s.connect_ex(ip_port)
      while True:
      msg = input('> : ').strip()
      if len(msg) == 0:
      continue
      if msg == 'quit':
      break
      s.send(msg.encode('utf-8'))
      length = s.recv(1024).decode('utf-8')
      s.send('recv_ready'.encode('utf-8'))
      send_size = 0
      recv_size = 0
      data = b''
      while recv_size < int(length):
      data += s.recv(1024)
      recv_size += len(data)
      print(data.decode('utf-8'), end='')
  • 基于UDP的命令执行程序

    • 服务器端

      import socket
      import subprocess
      ip_port = ('127.0.0.1', 9003)
      udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      udp_server.bind(ip_port)
      while True:
      cmd, addr = udp_server.recvfrom(1024)
      print('用户命令:', cmd, addr)
      res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
      stdout=subprocess.PIPE, stderr=subprocess.PIPE)
      stderr = res.stderr.read()
      stdout = res.stdout.read()
      udp_server.sendto(stdout + stderr, addr)
    • 客户端

      from socket import *
      import time
      ip_port = ('127.0.0.1', 9003)
      udp_client = socket(AF_INET, SOCK_DGRAM)
      while True:
      msg = input('> : ').strip()
      if len(msg) == 0:
      continue
      if msg == 'quit':
      break
      udp_client.sendto(msg.encode('utf-8'), ip_port)
      data, addr = udp_client.recvfrom(1024)
      print(data.decode('utf-8'), end='')
  • 粘包的解决办法

    • 普通青年版

      import socket
      import 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,
      stdout=subprocess.PIPE, stdin=subprocess.PIPE,
      stderr=subprocess.PIPE)
      err = res.stderr.read()
      stdout = res.stdout.read()
      data_length = len(stdout + err)
      conn.sendall(str(data_length).encode('utf-8'))
      data = conn.recv(1024).decode('utf-8')
      if data == 'recv_ready':
      conn.sendall(stdout + err)
      conn.close()
    • 客户端

      import socket
      import time
      ip_port = ('127.0.0.1', 8080)
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s.connect_ex(ip_port)
      while True:
      msg = input('> : ').strip()
      if len(msg) == 0:
      continue
      if msg == 'quit':
      break
      s.send(msg.encode('utf-8'))
      length = s.recv(1024).decode('utf-8')
      s.send('recv_ready'.encode('utf-8'))
      send_size = 0
      recv_size = 0
      data = b''
      while recv_size < int(length):
      data += s.recv(1024)
      recv_size += len(data)
      print(data.decode('utf-8'), end='')
  • 总结

    粘包问题在TCP通信中是常见的,主要由于面向流的特性导致。解决方法包括发送消息长度、自定义报头或使用第三方模块。选择合适的方法取决于具体需求和应用场景。

    上一篇:python入门开发学习笔记之粘包现象与解决方案
    下一篇:python入门开发学习笔记之类、实例、方法、属性详解

    发表评论

    最新留言

    很好
    [***.229.124.182]2025年05月12日 13时53分20秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章