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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python:粘包问题

發布時間:2025/3/20 python 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python:粘包问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

粘包現象

1 、tcp有粘包及udp無粘包

  • TCP 是面向連接的,面向流的可靠協議;發送端為了將多個發往接收端的包,更有效的發到對方,使用了優化方法(Nagle算法),將多次間隔較小且數據量小的數據,
    合并成一個大的數據塊,然后進行封包。這樣,接收端,就難于分辨出來了,必須提供科學的拆包機制面向流的通信是無消息保護邊界的。
  • UDP(用戶數據報協議)是無連接的,面向消息的,提供高效率服務。不會使用塊的合并優化算法,, 由于UDP支持的是一對多的模式,所以接收端的skbuff(套接字緩沖區)采用了鏈式結構來
    記錄每一個到達的UDP包,在每個UDP包中就有了消息頭(消息來源地址,端口等信息),這樣,對于接收端來說,就容易進行區分處理了。 即面向消息的通信是有消息保護邊界的。

注:tcp是基于數據流的,于是收發的消息不能為空,這就需要在客戶端和服務端都添加空消息的處理機制,防止程序卡住,
而udp是基于數據報的,即便是你輸入的是空內容(直接回車),那也不是空消息,udp協議會幫你封裝上消息頭

2 、產生原因:

1、接收端不知道消息的界限,不知道一次提取多少字節數據
2、TCP為提高傳輸效率,發送方往往要收集到足夠多的數據后才發送一個TCP段。若連續幾次需要send的數據都很少,
通常TCP會根據優化算法(Nagle算法)把這些數據合成一個TCP段后一次發送出去,這樣接收方就收到了粘包數據

產生粘包場景:(1)發送端需要等緩沖區滿才發送出去,造成粘包(發送數據時間間隔很短,數據了很小,會合到一起,產生粘包)
(2)接收方不及時接收緩沖區的包,造成多個包接收(客戶端發送了一段數據,服務端只收了一小部分,服務端下次再收的時候還是從緩沖區拿上次遺留的數據,產生粘包)

3 、解決方案
為字節流加上自定義固定長度報頭,報頭中包含字節流長度,然后一次send到對端,對端在接收時,先從緩存中取出定長的報頭,然后再取真實數據
struct 模塊

注:struct 模塊 把一個數字類型轉化為固定長度的bytes (struct.pack)打包 (struct.unpack)解包 res=(struct.pack('i',4855524)) #b'\x04\xe6\xe4\x02' 打包 print(res) print(struct .unpack('i',res)[0]) #解包

服務端:

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' import subprocess import socket import struct import json phone= socket.socket(socket.AF_INET ,socket.SOCK_STREAM ) phone.bind(('127.0.0.1',8080)) phone.listen(5) while True :conn,client=phone.accept()while True :try:cmd = conn.recv(1024)if len(cmd) == 0: break# 遠程執行命令obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, # 解碼stdout=subprocess.PIPE, # 正確信息stderr=subprocess.PIPE # 錯誤信息)stdout = obj.stdout.read()stderr = obj.stderr.read()#先制作報頭head_dic= {'filename':'a.txt','total_size':len(stdout)+len(stderr),'hash':'asdf165485221'}head_json = json.dumps(head_dic)head_bytes= head_json.encode('utf-8')#1、先把報頭的長度打包成四個bytes,然后發送conn.send(struct.pack('i',len(head_bytes)))#2、發送報頭conn.send(head_bytes)#3、發送真實數據conn.send(stdout )conn.send(stderr)except ConnectionResetError:breakconn.close()phone.close()

客戶端:

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' import struct import socket import json phone= socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone. connect(('127.0.0.1',8080)) while True :msg = input('<<<')if msg == 0:continue#phone.send(msg.encode('utf-8'))phone.send(bytes(msg,encoding='utf-8'))#1、先收4個字節,該4個字節包含報頭的長度 解包header_len=struct .unpack('i',phone.recv(4))[0]#2、通過報頭長度,再接受報頭內容header_bytes=phone.recv(header_len) #通過報頭長度,拿到bytes內容#從報頭中解析出想要的內容header_json=header_bytes .decode('utf-8') #報頭內容解碼得到字符串類型header_dic=json .loads(header_json) #反序列化得到字典print(header_dic)total_size = header_dic['total_size']#3、再收真實的數據recv_size =0 #初始值長度res=b'' #接收的具體值while recv_size< total_size:data= phone.recv(1024)res+=data # 拼接具體的值recv_size += len(data) #累加長度print(res.decode('gbk')) #收到的信息用GBK解碼 phone.close()

總結

以上是生活随笔為你收集整理的Python:粘包问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。