黏包現象主要發生在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'))
Linux tcp黏包解決方案
tcpip協議使用 流式 套接字 進行資料的傳輸,就是說它保證資料的可達以及資料抵達的順序,但並不保證資料是否在你接收的時候就到達,特別是為了提高效率,充分利用頻寬,底層會使用快取技術,具體的說就是使用nagle演算法將小的資料報放到一起傳送,但是這樣也帶來乙個使用上的問題 黏包,黏包就是說一次將多...
tcp和udp和黏包
tcp建立連線的過程 server端 import socket sk socket.socket 建立乙個socket物件 sk.bind 127.0.0.1 8088 繫結ip位址和埠 sk.listen while1 conn,addr sk.accept 等待建立連線 阻塞 直到連線建立才往...
關於TCP黏包問題
最近發現自己對於tcp通訊中的黏包問題還有疑問,查閱資料做下總結。一 tcp黏包問題 tcp黏包問題是因為傳送方把若干資料傳送,接收方收到資料時候黏在一包,從接受緩衝區來看,後一包的資料黏在前一包的尾部。二 黏包出現的原因 tcp黏包問題主要出現在兩個方面 1 傳送方問題 首先tcp會預設使用nag...