解決粘包問題

2022-08-10 07:48:15 字數 3812 閱讀 8129

注意注意注意:

res=subprocess.popen(cmd.decode('utf-8'),

shell=true,

stderr=subprocess.pipe,

stdout=subprocess.pipe)

的結果的編碼是以當前所在的系統為準的,如果是windows,那麼res.stdout.read()讀出的就是gbk編碼的,在接收端需要用gbk解碼,且只能從管道裡讀一次結果。

2、粘包現象

只有tcp有粘包現象,tcp協議是面向流的協議,這也是容易出現粘包問題的原因。例如基於tcp的套接字客戶端往服務端上傳檔案,傳送時檔案內容是按照一段一段的位元組流傳送的,在接收方看了,根本不知道該檔案的位元組流從何處開始,在何處結束。所謂粘包問題主要還是因為接收方不知道訊息之間的界限,不知道一次性提取多少位元組的資料所造成的。

此外,傳送方引起的粘包是由tcp協議本身造成的,tcp為提高傳輸效率,傳送方往往要收集到足夠多的資料後才傳送乙個tcp段。若連續幾次需要send的資料都很少,通常tcp會根據優化演算法把這些資料合成乙個tcp段後一次傳送出去,這樣接收方就收到了粘包資料。

兩種情況下會發生粘包。

傳送端需要等緩衝區滿才傳送出去,造成粘包(傳送資料時間間隔很短,資料了很小,會合到一起,產生粘包)

接收方不及時接收緩衝區的包,造成多個包接收(客戶端傳送了一段資料,服務端只收了一小部分,服務端下次再收的時候還是從緩衝區拿上次遺留的資料,產生粘包) 

解決辦法1:

服務端:

import socket

import subprocess

import struct

phone=socket.socket(socket.af_inet,socket.sock_stream)

phone.bind(('127.0.0.1',8090))

phone.listen(5)

print('starting...')

while true:

conn,addr=phone.accept()

print('ip:%s,port:%s'%(addr[0],addr[1]))

while true:

try:

cmd=conn.recv(1024)

#執行命令cmd

obj=subprocess.popen(cmd.decode('utf-8'),shell=true,

stdout=subprocess.pipe,

stderr=subprocess.pipe)

stdout=obj.stdout.read()

stderr=obj.stderr.read()

#傳送真實資料的描述資訊:長度

header=struct.pack('i',len(stdout)+len(stderr)) #i模式為針對整數型資料,下輸出的結果為4

conn.send(header)

# 傳送真實資料

conn.send(stdout)

conn.send(stderr)

except exception:

break

conn.close()

phone.close()

客戶端:

import socket

import struct

phone=socket.socket(socket.af_inet,socket.sock_stream)

phone.connect(('127.0.0.1',8090))

while true:

cmd=input('>>>').strip()

phone.send(cmd.encode('utf-8'))

header=phone.recv(4) #指定接收4個位元組

total_size=struct.unpack('i',header)[0]#對接收的4個位元組資料進行解包得到待接收資料大小的元組:(資料大小,)

#迴圈接收資料

total_data=b''

recv_size=0

while recv_size

由於模組struct的pack方法中使用的i型別存在整數無限大時會出現報錯的弊端,故提出如下解決方案:

解決辦法2:

服務端:

import socket

import subprocess

import struct

import json

phone=socket.socket(socket.af_inet,socket.sock_stream)

phone.bind(('127.0.0.1',8090))

phone.listen(5)

print('starting...')

while true:

conn,addr=phone.accept()

print('ip:%s,port:%s'%(addr[0],addr[1]))

while true:

try:

cmd=conn.recv(1024)

if not cmd:break

obj=subprocess.popen(cmd.decode('utf-8'),shell=true,

stdout=subprocess.pipe,

stderr=subprocess.pipe)

stdout=obj.stdout.read()

stderr=obj.stderr.read()

#製作報頭

header_dic=

header_json=json.dumps(header_dic)

header_bytes=header_json.encode('utf-8')

#傳送報頭長度

conn.send(struct.pack('i',len(header_bytes)))

#傳送報頭

conn.send(header_bytes)

#傳送資料

conn.send(stdout)

conn.send(stderr)

except exception:

break

conn.close()

phone.close()

客戶端:

import socket

import struct

import json

phone=socket.socket(socket.af_inet,socket.sock_stream)

phone.connect(('127.0.0.1',8090))

while true:

cmd=input('>>>').strip()

if not cmd:continue

phone.send(cmd.encode('utf-8'))

# 接收報頭內容長度

obj=phone.recv(4)

header_size=struct.unpack('i',obj)[0]

#接收報頭字典

header_bytes=phone.recv(header_size)

header_json=header_bytes.decode('utf-8')

header_dic=json.loads(header_json)

total_size=header_dic['total_size']

total_data=b''

recv_size=0

while recv_size

解決粘包問題

要知道!所謂粘包問題主要還是因為接收方不知道訊息之間的界限,不知道一次性提取多少位元組的資料所造成的。要解決粘包不外乎乙個條件,就是知道取多少,讓對方事先知道我們要發多少位元組的資料,然後造乙個容器,每次規定的往容器裡面倒水,當水快滿的時候,量出最後一勺還需要多少勺多少的水,最後把這水不多不少的往容...

解決粘包問題(python)

在傳輸資料訊息時因為tcp協議使用了優化方法 nagle演算法 將多次間隔較小且資料量小的資料,合併成乙個大的資料塊,然後進行封包,這樣,接收端就難於分辨出來了,所以會產生粘包效果。在這種情況下我們需要製作乙個報頭來告訴接收端我們要傳送的資料的長度,來方便接收端接收。第一步 製作固定長度的報頭 he...

Python Day33 粘包問題及粘包解決方案

tcp粘包問題 python 粘包指的是資料與資料之間沒有明確的分界線,導致不能正確讀取資料!tcp協議也稱之為流式協議 udp稱為資料報協議 應用程式無法直接操作硬體,應用程式想要傳送資料則必須將資料交給作業系統,而作業系統需要需要同時為所有應用程式提供資料傳輸服務,也就意味著,作業系統不可能立馬...