首頁 > 軟體

Python資料傳輸黏包問題

2022-04-11 22:00:11

1.socket黏包問題原理

黏包:指資料與資料之間沒有明確的分界線,導致不能正確的讀取資料。

應用資料想要傳送資料就必須將資料交給作業系統,而作業系統需要同時為所有的應用程式提供資料傳輸服務,就意味著不可能馬上將應用資料傳送,就需要為程式提供一個緩衝區,用於臨時存放資料。

當傳送資料很快,有兩條資料都在緩衝區時,作業系統可能將兩個資料發給接收方,資料之間沒有分界線,接收方會誤認為是一條資料。

2.UDP協定

UDP在收發資料時是基於封包的,即一個包一個包的傳送,包與包之間有明確的分界,到達對方緩衝區後也是獨立封包。這種方式存在的問題:

①傳送資料的長度每個作業系統會有不同的限制,資料超過限制則無法傳送;

②接收方接收資料時,如果應用程式提供的快取容量小於封包的長度,則會造成資料的丟失,而緩衝區大小不可能無限大。

這意味著UDP不會出現黏包問題,但會丟失資料,不可靠。

3.TCP協定

TCP增加了一套校驗規則來保證資料的完整性,會將超過TCP包最大長度的資料拆分為多個TCP包,並在傳輸資料時為每一個TCP封包指定一個順序號,接收方在收到TCP封包後按照順序將封包進行重組,重組後的資料全都是二進位制資料,且每次收到的二進位制資料之間沒有明顯的分界。基於這種工作機制,TCP在三種情況下發生黏包問題:

①當單個封包較小時,接收方可能一次性讀取了多個包的資料;

②當整體資料較大時,接收方可能一次性僅讀取了一個包的一部分內容;

③另外TCP協定為提高效率,增加了一種優化機制,會將資料小且傳送間隔短的資料合併行送,該機制也會導致傳送方將兩個封包粘在一起傳送。

也就是說,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資料傳輸黏包內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com