標籤:png pwd struct blank res 防止 lis ndt recv
黏包現象
基於tcp先製作一個遠程執行命令的程式(命令ls -l ; lllllll ; pwd)
res=subprocess.Popen(cmd.decode(‘utf-8‘),shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE)的結果的編碼是以當前所在的系統為準的,如果是windows,那麼res.stdout.read()讀出的就是GBK編碼的,在接收端需要用GBK解碼且只能從管道裡讀一次結果
同時執行多條命令之後,得到的結果很可能只有一部分,在執行其他命令的時候又接收到之前執行的另外一部分結果,這種顯現就是黏包。
基於tcp協議實現的黏包
import socketimport subprocesssk = socket.socket()sk.connect((‘127.0.0.1‘,8090))while True: cmd = sk.recv(1024).decode(‘gbk‘) ret = subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) std_out = ‘stdout :‘+(ret.stdout.read()).decode(‘gbk‘) std_err = ‘stderr :‘+(ret.stderr.read()).decode(‘gbk‘) print(std_out) print(std_err) sk.send(std_out.encode(‘utf-8‘)) sk.send(std_err.encode(‘utf-8‘))sk.close()
import socketsk = socket.socket()sk.bind((‘127.0.0.1‘,8090))sk.listen()conn,addr = sk.accept()while True: cmd = input(‘>>>‘) conn.send(cmd.encode(‘utf-8‘)) ret = conn.recv(1024).decode(‘utf-8‘) print(ret)conn.close()sk.close()
基於udp協議實現的黏包
import socketimport subprocesssk = socket.socket(type=socket.SOCK_DGRAM)addr = (‘127.0.0.1‘,8090)sk.sendto(‘吃了麼‘.encode(‘utf-8‘),addr)while True: cmd,addr = sk.recvfrom(10000) ret = subprocess.Popen(cmd.decode(‘gbk‘),shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) std_out = ‘stdout :‘+(ret.stdout.read()).decode(‘gbk‘) std_err = ‘stderr :‘+(ret.stderr.read()).decode(‘gbk‘) print(std_out) print(std_err) sk.sendto(std_out.encode(‘utf-8‘),addr) sk.sendto(std_err.encode(‘utf-8‘),addr)sk.close()
import socketsk = socket.socket(type=socket.SOCK_DGRAM)sk.bind((‘127.0.0.1‘,8090))msg,addr = sk.recvfrom(10240)while True: cmd = input(‘>>>‘) if cmd == ‘q‘: break sk.sendto(cmd.encode(‘utf-8‘),addr) msg,addr = sk.recvfrom(10240) print(msg.decode(‘utf-8‘))sk.close()# udp# udp 不會黏包# udp 會丟包
注意:只有TCP有粘包現象,UDP永遠不會粘包
基於tcp協議特點的黏包現象成因
例如基於tcp的通訊端用戶端往服務端上傳檔案,發送時檔案內容是按照一段一段的位元組流發送的,在接收方看了,根本不知道該檔案的位元組流從何處開始,在何處結束
此外,發送方引起的粘包是由TCP協議本身造成的,TCP為提高傳輸效率,發送方往往要收集到足夠多的資料後才發送一個TCP段。若連續幾次需要send的資料都很少,通常TCP會根據最佳化演算法把這些資料合成一個TCP段後一次發送出去,這樣接收方就收到了粘包資料。
UDP不會發生黏包
UDP(user datagram protocol,使用者資料包通訊協定)是不需連線的,面向訊息的,提供高效率服務。 不會使用塊的合并最佳化演算法,, 由於UDP支援的是一對多的模式,所以接收端的skbuff(通訊端緩衝區)採用了鏈式結構來記錄每一個到達的UDP包,在每個UDP包中就有了訊息頭(訊息來源地址,連接埠等資訊),這樣,對於接收端來說,就容易進行區分處理了。 即面向訊息的通訊是有訊息保護邊界的。 對於空訊息:tcp是基於資料流的,於是收發的訊息不可為空,這就需要在用戶端和服務端都添加空訊息的處理機制,防止程式卡住,而udp是基於資料報的,即便是你輸入的是空內容(直接斷行符號),也可以被發送,udp協議會幫你封裝上訊息頭髮送過去。 不可靠不黏包的udp協議:udp的recvfrom是阻塞的,一個recvfrom(x)必須對唯一一個sendinto(y),收完了x個位元組的資料就算完成,若是y;x資料就丟失,這意味著udp根本不會粘包,但是會丟資料,不可靠。
python——黏包