Python网络编程中TCP黏包问题的原理与成因解析
本文深入解析Python网络编程中常见的黏包现象。通过对比UDP与TCP协议机制,阐明TCP因缓冲区合并、分包重组及小数据合并发送导致的黏包成因,并区分发送方与接收方视角下的具体表现,帮助开发者理解数据边界缺失的根本原因。
1. Socket黏包问题原理
所谓黏包,是指发送的数据流之间缺乏明确的分隔标识,导致接收端无法准确区分数据边界,从而无法正确解析读取数据。
应用程序在发送数据时,必须先将数据交由操作系统处理。由于操作系统需同时为多个应用程序提供数据传输服务,无法立即发送所有应用数据,因此会引入缓冲区机制,用于临时存储待发送的数据。
当数据发送速度较快,多条数据同时存在于缓冲区时,操作系统可能将这些数据合并发送给接收方。由于数据间没有分隔符,接收方会将这多条数据误判为一条完整的数据。
2. UDP协议
UDP协议在数据传输时基于数据包机制,即按包为单位进行发送,包与包之间存在明确的分界,到达接收方缓冲区后仍保持为独立的数据包。然而,这种方式存在以下局限性:
① 不同操作系统对单个数据包的最大长度限制不同,若数据长度超过该限制,则无法发送;
② 接收方在接收数据时,若应用程序提供的缓冲区容量小于数据包长度,将导致数据丢失,而缓冲区大小不可能无限大。
综上所述,UDP协议虽然不会出现黏包问题,但存在数据丢失的风险,属于不可靠传输。
3. TCP协议
TCP协议通过增加校验机制来保证数据完整性。当数据超过TCP包最大长度时,TCP会将数据拆分为多个TCP包,并为每个数据包指定顺序号。接收方收到数据包后,按顺序号进行重组。重组后的数据均为二进制数据,且每次接收到的二进制数据之间没有明显的分界。基于此工作机制,TCP在以下三种情况下容易发生黏包问题:
① 当单个数据包较小时,接收方可能一次性读取了多个包的数据;
② 当整体数据较大时,接收方可能一次性仅读取了一个包的部分内容;
③ 此外,TCP协议为提高传输效率,引入了一种优化机制(Nagle算法),会将发送间隔短且数据量小的数据包合并发送,该机制也会导致发送方将两个数据包粘在一起发送。
也就是说,TCP传输数据是可靠的,但是会黏包。
4. 发送方出现的黏包
服务器端:
from socket import *
server_socket = socket(AF_INET,SOCK_STREAM)
server_socket.bind(('',8080))
server_socket.listen(5)
new_socket,client_addr = server_socket.accept()
data1 = new_socket.recv(1024)
data2 = new_socket.recv(1024)
print("收到的第一条数据:",data1)
print("收到的第二条数据:",data2)
new_socket.close()
server_socket.close()客户端:
from socket import *
client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(('10.175.193.126',8080))
client_socket.send('hello'.encode('utf-8'))
client_socket.send('word'.encode('utf-8'))
client_socket.close()服务器端接收到的数据:

由于客户端两条数据发送间隔太短且数据包太小,被服务器端误认为是一条数据。
5. 接收方出现的黏包
服务器端:
from socket import *
import time
server_socket = socket(AF_INET,SOCK_STREAM)
server_socket.bind(('',8080))
server_socket.listen(5)
new_socket,client_addr = server_socket.accept()
print("连接成功!",client_addr)
data1 = new_socket.recv(3) #每次只接收三个字节,接收不完整
time.sleep(6)
print("收到的第一条数据:",data1)
data2 = new_socket.recv(10)
#接收第一次未接收的数据,若有空间,会继续接收新数据
print("收到的第二条数据:",data2)
new_socket.close()
server_socket.close()客户端:
from socket import *
#通过time模块使客户端发送多个数据包时,时间间隔变长
import time
client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(('10.175.193.126',8080))
client_socket.send('hello'.encode('utf-8'))
time.sleep(5) #让当前线程休眠5秒
client_socket.send('word'.encode('utf-8'))
client_socket.close()服务器端接收到的数据:

6. 黏包的成因
① 服务器端出现黏包:接收方不知道消息之间的界限,不知道一个消息要提取多少字节的数据造成的;
② 客户端出现黏包:TCP在发送数据少且间隔时间短的数据包时,会将几条合并一起发送。
到此这篇关于Python数据传输黏包问题的文章就介绍到这了,更多相关Python数据传输黏包内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









