日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python 套接字 struck_Python socket粘包问题(最终解决办法)

發(fā)布時間:2024/9/27 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 套接字 struck_Python socket粘包问题(最终解决办法) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

套接字:

就是將傳輸層以下的協(xié)議封裝成子接口

對于應(yīng)用程序來說只需調(diào)用套接字的接口,寫出的程序自然是遵循tcp或udp協(xié)議的

實(shí)現(xiàn)第一個功能個:

實(shí)現(xiàn):通過客戶端向服務(wù)端發(fā)送命令,調(diào)取windows下面的cmd窗口,將服務(wù)端執(zhí)行命令的結(jié)構(gòu),返回并顯示在

客戶端窗口上。

subprocess:

1.可以將執(zhí)行結(jié)果返回

2.返回值是bytes類型

(基于這兩點(diǎn),可以應(yīng)用在server端,將服務(wù)端的返回直接以bytes的格式直接send給客戶端,

實(shí)現(xiàn)在客戶端的顯示)

問題1:粘包問題

粘包問題:實(shí)際是由TCP協(xié)議在傳輸數(shù)據(jù)時的2大特性來的

TCP協(xié)議又叫流式協(xié)議,在數(shù)據(jù)傳輸上,只要客戶端發(fā)送相應(yīng)的數(shù)據(jù)請求,

服務(wù)端會將數(shù)據(jù)像流水一樣不斷的send給客戶端

基于這個特點(diǎn),就會存在一個問題,當(dāng)客戶端給服務(wù)端發(fā)送一條命令,服務(wù)端成功接收并將命令的

結(jié)果返回到客戶端的時候,由于客戶端recv()的數(shù)量限制,可以一次不能完全取出,

這個時候就會存在,下次輸入命令客戶端首先拿到的返回值就是上次殘留的沒有收完的數(shù)據(jù)

基于粘包問題的解決思路就是:

發(fā)數(shù)據(jù)之前先把報頭發(fā)給對方,讓對方先知道要收的報頭的長度,后面再傳數(shù)據(jù)文件

自定義報頭:

為甚么要自定義報頭:

因?yàn)閟truck path(‘i’,3443242)

1.’i‘:類型不同,后面數(shù)字的長度大小也不同,大小是有限的(當(dāng)超出范圍時會報錯)

2.因?yàn)閳箢^里面含有的內(nèi)容可能不僅僅只有total_siz還有filename、hash等等,知識單純的把total_size

當(dāng)做報頭傳入不合理,所以我們要自定義報頭

Server端配置

from socket import *

importsocket,subprocess,struct,json

server=socket.socket(AF_INET, SOCK_STREAM)

server.bind(('127.0.0.1', 8080))

server.listen(5)whileTrue:

conn,client=server.accept()print(client)whileTrue:try:

cmd= conn.recv(1024)if len(cmd) == 0: breakobj=subprocess.Popen(

cmd.decode('utf-8'),

shell=True,

stdout=subprocess.PIPE,

stderr=subprocess.PIPE,

)

out=obj.stdout.read()

err=obj.stderr.read()#制作報頭

header_dic={'filename':'a.txt','total_size':len(out)+len(err),'hash':'abc32i5o24'}#對包頭進(jìn)行序列化

header_json=json.dumps(header_dic) #字符串格式

header_bytes=header_json.encode('utf-8')#1.先發(fā)型報頭的長度 len(header_bytes) struck為固定的4個字節(jié)

conn.send(struct.pack('i',len(header_bytes)))#2.發(fā)送報頭

conn.send(header_bytes)#3.發(fā)送真是數(shù)據(jù)

conn.send(out)

conn.send(err)exceptConnectionResetError:breakconn.close()

server.close()

Client端配置

from socket import *

importsocket,struct,json

client=socket.socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8080))whileTrue:

cmd=input('輸入你要操作的命令:')

client.send(cmd.encode('utf-8'))if len(cmd) == 0:continue

#1.先收報頭的四個字節(jié),首先拿到報頭傳來的長度-》bytes

header=client.recv(4) #i類型足夠了 header為bytes類型

header_size=struct.unpack('i',header)[0] #拿到元祖形式,取第一個就是整個報頭的長度   print(header_size) ?#為報頭的長度值

#2.再收報頭(對應(yīng)服務(wù)端的conn.send(header_bytes))

header_bytes=client.recv(header_size) #根據(jù)報頭的固定長度去收接收

#3.解析包頭(就是將header_bytes文件先解碼成json格式)

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

header_dic=json.loads(header_str)print(header_dic)

total_size=header_dic['total_size']print(total_size)

recv_size=0 #定義一個初始的接收變量為0,只是個計數(shù)變量,為了統(tǒng)計與總的total_size的len大小

res=b''

while recv_size

recv_data=client.recv(1024) #每次傳過來的recv_data是bytes類型

res+=recv_data

recv_size+=len(recv_data) #循環(huán)增加每次接收值的長度#cmd=client.recv(1024)

print(res.decode('gbk'))

client.close()

粘包問題的最終解決方案,分析:

服務(wù)端:

目的為了自定義報頭(報頭中不僅包含長度,可能還有文件名等信息)

subprocess

...1.制作報頭(字典形式)

header_dic={'filename':'a.txt','total_size':len(out)+len(err),'hash':'abc32i5o24'}2.通過json將報頭序列化再encode為bytes類型

header_json=json.dumps(header_dic) #字符串類型

header_bytes=header_json.encode('utf-8') #bytes類型

3.發(fā)送報頭的長度,struck目的是固定封裝好的報頭為4個字節(jié)長度 =====對應(yīng)客戶端剛開始 header=client.recv(4)

struck:1.將數(shù)字轉(zhuǎn)為bytes類型,保證發(fā)送過去的是bytes類型 2.固定4個字節(jié)

第一次發(fā):conn.send(struck.pack('i',len(header_bytes)))

先傳給客戶端固定了收的時候報頭的長度,不至于報頭和其他內(nèi)容粘在一起4.發(fā)送報頭 =======對應(yīng)客戶端接收報頭 header_bytes=client.recv(header_size)

第二次發(fā):conn.send(header_bytes)5.發(fā)送真實(shí)的數(shù)據(jù)

conn.send(out)

conn.send(err)

客戶端:(bytes--int)1.通過服務(wù)端返回的字節(jié),拿到報頭的的長度

header=client.recv(4) #header是4個bytes字節(jié)

header_size=struck.unpack('i',header)[0] #字節(jié)頭-拿到int大小

2.再收報頭

header_bytes=client.recv(header_size) #bytes類型

3.解析報頭(1.先把內(nèi)存中存放的bytes類型,用decode('utf-8')解碼為字符串)

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

header_dic=json.loads(header_json) #json反序列化出字典格式 (對應(yīng)server第2步)

print(header_dic)4.拿到字典中的報頭大小

total_size=header_dic['total_size']print(total_size)

struck功能輔助理解:所以客戶端剛開始接收4 大小是足夠把報頭接收完的。

#struck工鞥理解:importstruct#將整型轉(zhuǎn)成bytes

res=struct.pack('i',1232435436)print(res,len(res)) #res:為bytes類型,還是固定長度4(一般情況已經(jīng)可以包含很多)

#將bytes轉(zhuǎn)成整型

aa=struct.unpack('i',res)print(aa,aa[0],type(aa)) #

print(len(res)) #4 一般情況多數(shù)bytes 4個長度足夠了

"""結(jié)果

b'\xecxuI' 4

(1232435436,) 1232435436

4"""

總結(jié)

以上是生活随笔為你收集整理的python 套接字 struck_Python socket粘包问题(最终解决办法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。