
python入门开发学习笔记之粘包现象与解决方案
TCP是面向流的协议:TCP不关心每个消息的大小,会将多个消息合并成一个大块发送,导致接收方难以识别消息的界限。 发送方和接收方的缓冲区:数据在传输过程中会被临时存储,可能导致部分数据被拆分或延迟发送。 发送消息长度:发送方在发送数据前发送消息的长度,接收方根据长度等待完整数据。 自定义报头:在消息前添加固定长度的报头,包含消息的总大小和其他元数据,确保接收方可以准确识别消息界限。 使用第三方模块:如struct模块,自定义报头和数据格式,确保数据传输的准确性和完整性。
发布日期:2025-05-13 01:15:46
浏览次数:2
分类:精选文章
本文共 4136 字,大约阅读时间需要 13 分钟。
粘包问题是指在使用TCP协议时,客户端和服务器端可能会收到多个消息粘在一起,导致接收端无法正确识别消息的界限。这种现象常见于远程执行命令程序中,尤其是在发送大量数据或长输出时。
粘包问题的原因
解决粘包问题的方法
实现方法
简单远程执行命令程序开发:
-
服务器端:
import socketimport subprocessip_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 socketimport timeip_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 socketimport subprocessip_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 timeip_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 socketimport subprocessip_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 socketimport timeip_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通信中是常见的,主要由于面向流的特性导致。解决方法包括发送消息长度、自定义报头或使用第三方模块。选择合适的方法取决于具体需求和应用场景。
发表评论
最新留言
很好
[***.229.124.182]2025年05月12日 13时53分20秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
LeetCode-Isomorphic Strings
2025-04-05
LeetCode.两数之和&三数之和&最接近的三数之和&四数之和
2025-04-05
LeetCode110.平衡二叉树
2025-04-05
LeetCode111.二叉树最小深度
2025-04-05