python学习day32 黏包 struct模块
為什么會出現黏包問題??
首先只有在TCP協議中才會出現黏包現象
是因為TCP協議是面向流的協議
在發送的數據 傳輸過程中 有緩存機制 來避免數據丟失
因此 在連續發送小數據的時候 以及接收大小不符的時候都容易出現黏包現象
本質還是因為我們在接受數據的時候不知道發送的數據的長短
怎么解決黏包問題?
在接收端發送要發送的數據的大小
一種是不帶struct??一種是帶struct? 定制協議
?
黏包
http://www.cnblogs.com/Eva-J/articles/8244551.html#_label5
?注意:只有TCP有粘包現象,UDP永遠不會粘包
黏包成因:
多個send可能會發生黏包現象
優化算法不優化
發生黏包兩種現象:
情況一 發送方的緩存機制
發送端需要等緩沖區滿才發送出去,造成粘包(發送數據時間間隔很短,數據了很小,會合到一起,產生粘包)
情況二 接收方的緩存機制
接收方不及時接收緩沖區的包,造成多個包接收(客戶端發送了一段數據,服務端只收了一小部分,服務端下次再收的時候還是從緩沖區拿上次遺留的數據,產生粘包)
?
?如何解決黏包?
存在的問題: 多了一次交互。程序的運行速度遠快于網絡傳輸速度,所以在發送一段字節前,先用send去發送該字節流長度,這種方式會放大網絡延遲帶來的性能損耗struct模塊
該模塊可以把一個類型,如數字,轉成固定長度的bytes
這個模塊可以把要發送的數據長度轉換成固定長度的字節。這樣客戶端每次接收消息之前只要先接受這個固定長度字節的內容看一看接下來要接收的信息大小,那么最終接受的數據只要達到這個值就停止,就能剛好不多不少的接收完整的數據了。
?
import structret = struct.pack('i', 2049) # pack方法,將對象轉換成固定字節長度bytes類型 num = struct.unpack('i', ret) # 解包 print(num) # 元組 print(num[0]) # 數字?
?
連續send? 連續receive
?
我們在網絡上傳輸的所有數據,都叫數據包
數據包中的數據,都叫報文
報文里不只有你的數據 ip地址 mac地址 端口號
所有的報文都有報頭? 相當于協議 接收多少字節 什么順序 等等
報頭可以自己定制
根據報頭來解包接收的數據
復雜的應用上就會用到定制報頭
比如:傳輸文件的時候
文件名、大小、類型、路徑
?
網絡傳輸中,處處有有協議,協議就是一堆報文和報頭 ———字節
協議的解析過程我們不需要關心
我們也可以自定制協議
?
?實現一個大文件的上傳或下載:
客戶端作發送端:
import socket import os import json import structsk = socket.socket() sk.connect(('127.0.0.1',8090))# 發文件 # 定制報頭 head = {'filepath':r'H:\python\day32','filename':r'05 python fullstack s9day32 strcuct模塊定制報頭的理論.mp4','filesize':None} file_path = os.path.join(head['filepath'],head['filename']) file_size = os.path.getsize(filepath) head['filesize'] = file_sizejson_head = json.dumps(head) # 字典轉成字符串 bytes_head = json_head.encode('utf-8') # 字符串轉bytes類型 head_len = len(bytes_head) # 報頭的長度 pack_len = struct.pack('i', head_len) # 報頭長度轉成固定的4字節長度 sk.send(pack_len) # 先發報頭長度 sk.send(bytes_head) # 再發報頭內容 # 然后再發文件內容: buffer = 1024 with open(filepath, 'rb') as f:while file_size:if file_size >= buffer:content = f.read(buffer)sk.send(content)file_size -= bufferelse:content = f.read(file_size)sk.send(content)break sk.close服務端:
import socket import os import json import structsk = socket.socket() sk.bind(('127.0.0.1',8090)) sk.listen()conn, addr = sk.accept() # 接收 head_len = conn.recv(4) # 接收報頭長度 head_len = struct.unpack('i', head_len)[0] # 解包成元組 第一個 json_head = conn.recv(head_len).decode('utf-8') head = json.loads(json_head) # 報頭 filesize = head['filesize'] buffer = 1024 # 寫入文件 with open(head['filename'], 'wb') as f:while filesize:if filesize >= buffer:content = conn.recv(buffer)f.write(content)filesize -= bufferelse:f.write(conn.recv(filesize))breakconn.close sk.close?
轉載于:https://www.cnblogs.com/happyfan/p/10450905.html
總結
以上是生活随笔為你收集整理的python学习day32 黏包 struct模块的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Visual Studio 快捷键使用方
- 下一篇: UG软件盗版