python之黏包和黏包解決方案

2021-09-08 07:27:55 字數 3503 閱讀 5016

黏包現象主要發生在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...