1. 程式人生 > >Python中出現黏包應該如何解決?

Python中出現黏包應該如何解決?

在這裡插入圖片描述
Python中黏包現象主要發生在TCP連線, 基於TCP的套接字客戶端往服務端上傳檔案,傳送時檔案內容是按照一段一段的位元組流傳送的,在接收方看來,根本不知道該檔案的位元組流從何處開始,在何處結束.
兩種黏包現象:
1 連續的小包可能會被優化演算法給組合到一起進行傳送
2 第一次如果傳送的資料大小2000B接收端一次性接受大小為1024,這就導致剩下的內容會被下一次recv接收到,導致結果錯亂
解決黏包現象的兩種方案:
方案一:由於雙方不知道對方傳送資料的長度,導致接收的時候,可能接收不全,或者多接收另外一次傳送的資訊內容,所以在傳送真實資料之前,要先發送資料的長度,接收端根據長度來接收後面的真實資料,但是雙方有一個互動確認的過程
#服務端
import socket
import subprocess
server = socket.socket()
ip_port = (‘127.0.0.1’,8001)server.bind(ip_port)server.listen()conn,addr = server.accept()while 1:
from_client_cmd = conn.recv(1024) print(from_client_cmd.decode(‘utf-8’))
#接收到客戶端傳送來的系統指令,我服務端通過subprocess模組到服務端自己的系統裡面執行這條指令
sub_obj = subprocess.Popen(
from_client_cmd.decode(‘utf-8’),
shell=True,
stdout=subprocess.PIPE, #正確結果的存放位置
stderr=subprocess.PIPE #錯誤結果的存放位置
)
#從管道里面拿出結果,通過subprocess.Popen的例項化物件.stdout.read()方法來獲取管道中的結果
std_msg = sub_obj.stdout.read() #為了解決黏包現象,我們統計了一下訊息的長度,先將訊息的長度傳送給客戶端,客戶端通過這個長度來接收後面我們要傳送的真實資料
std_msg_len = len(std_msg)
# std_bytes_len = bytes(str(len(std_msg)),encoding=‘utf-8’)
#首先將資料長度的資料型別轉換為bytes型別
std_bytes_len = str(len(std_msg)).encode(‘utf-8’)
print(‘指令的執行結果長度>>>>’,len(std_msg))
conn.send(std_bytes_len) status = conn.recv(1024)
if status.decode(‘utf-8’) == ‘ok’: conn.send(std_msg)
else:
pass# 客戶端
import socketclient = socket.socket()
client.connect((‘127.0.0.1’,8001))while 1:
cmd = input(‘請輸入指令:’)
client.send(cmd.encode(‘utf-8’)) server_res_len = client.recv(1024).decode(‘utf-8’)
print(‘來自服務端的訊息長度’,server_res_len) client.send(b’ok’) server_cmd_result = client.recv(int(server_res_len))
print(server_cmd_result.decode(‘gbk’))
方案二:
  Struct模組,
  打包:struct.pack(‘i’,長度)
  解包:struct.unpack(‘i’,位元組)
#服務端
import socket
import subprocess
import struct
server = socket.socket()
ip_port = (‘127.0.0.1’,8001)server.bind(ip_port)server.listen()conn,addr = server.accept()while 1:
from_client_cmd = conn.recv(1024) print(from_client_cmd.decode(‘utf-8’))
#接收到客戶端傳送來的系統指令,我服務端通過subprocess模組到服務端自己的系統裡面執行這條指令
sub_obj = subprocess.Popen(
from_client_cmd.decode(‘utf-8’),
shell=True,
stdout=subprocess.PIPE, #正確結果的存放位置
stderr=subprocess.PIPE #錯誤結果的存放位置
)
#從管道里面拿出結果,通過subprocess.Popen的例項化物件.stdout.read()方法來獲取管道中的結果
std_msg = sub_obj.stdout.read() #為了解決黏包現象,我們統計了一下訊息的長度,先將訊息的長度傳送給客戶端,客戶端通過這個長度來接收後面我們要傳送的真實資料
std_msg_len = len(std_msg) print(‘指令的執行結果長度>>>>’,len(std_msg))
msg_lenint_struct = struct.pack(‘i’,std_msg_len)
conn.send(msg_lenint_struct+std_msg)
#客戶端
import socket
import struct
client = socket.socket()
client.connect((‘127.0.0.1’,8001))while 1:
cmd = input(‘請輸入指令:’)
#傳送指令
client.send(cmd.encode(‘utf-8’)) #接收資料長度,首先接收4個位元組長度的資料,因為這個4個位元組是長度
server_res_len = client.recv(4)
msg_len = struct.unpack(‘i’,server_res_len)[0] print(‘來自服務端的訊息長度’,msg_len)
#通過解包出來的長度,來接收後面的真實資料
server_cmd_result = client.recv(msg_len)
print(server_cmd_result.decode(‘gbk’))
文章來自:

https://www.itjmd.com/news/show-5331.html