黏包現象主要發生在TCP連接, 基於TCP的套接字客戶端往服務端上傳文件,發送時文件內容是按照一段一段的位元組流發送的,在接收方看來,根本不知道該文件的位元組流從何處開始,在何處結束. 兩種黏包現象: 1 連續的小包可能會被優化演算法給組合到一起進行發送 2 第一次如果發送的數據大小2000B接收端一次性 ...
黏包現象主要發生在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 socket client = 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'))