tcp是流體協定. 其nagle演演算法會將資料量較小. 並且傳送間隔時間較短的多個封包合併為一個傳送. 網路傳輸的時候是一段一段位元組流的傳送. 在接收方看來根本不知道位元組流從何開始. 在哪裡結束. 所以粘包問題就是接收方不知道訊息之間的界限. 不止到一次性提取多少資料導致的
而udp協定的是訊息導向(資料包)的協定. 每一段的udp都是一段訊息. 應用程式必須以訊息作為單位提取. 不能提取任意自己的資料. 而且udp協定並不建立連線. 只管傳送不管對方是否收到. 所以不存在粘包問題
設定一個固定的報頭. 報頭中含有真實資料的長度資訊. 然後使用者端就可以根據報頭的資料去接收相應位元組. 從而避免粘包現象. 總結起來就是一開始將真實資料長度通過報頭傳遞給使用者端. 後面都是環環相扣
前面都是理論部分. 後面咱們來看看怎麼進行實操解決粘包問題. 解決粘包問題的關鍵就是讓使用者端知道資料之間的界限在哪.
# 伺服器端.py
# -*- encoding:utf-8 -*-
# @time: 2022/7/30 13:07
# @author: Maxs_hu
"""
以前有種比較low的方式(alex)是使用time.sleep將資料流之間斷開. 當然這種自己設定網路延遲的方式當然是不可取的
"""
from socket import *
import subprocess
import json
import struct
socket = socket(AF_INET, SOCK_STREAM)
socket.bind(('127.0.0.1', 8000))
socket.listen(5)
while True: # 連結迴圈
print('---伺服器開始執行---')
conn, client_addr = socket.accept()
print(client_addr)
while True:
try:
cmd = conn.recv(1024)
if len(cmd) == 0:
break
obj = subprocess.run(cmd.decode('utf8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding='gbk'
)
stdout = obj.stdout.encode('utf8')
stderr = obj.stderr.encode('utf8')
data_size = len(stderr+stdout)
# 1. 製作合理的表頭資料
header_dic = {
'filename': 'a.txt',
'total_size': data_size,
'hashlib': 'fdfadfadf343jkafjdxkfjc'
}
# 將字典轉化成可以傳輸的格式. 並計算出len
header_json = json.dumps(header_dic)
header_byte = header_json.encode('utf8')
header_len = struct.pack('i', len(header_byte))
# 1. 先將表頭長度進行傳遞
conn.send(header_len)
# 2. 再將表頭資料進行傳輸
conn.send(header_byte)
# 3. 在傳輸真實的資料
conn.send(stderr+stdout)
except ConnectionResetError:
break
conn.close()
# 使用者端.py
# -*- encoding:utf-8 -*-
# @time: 2022/7/30 13:07
# @author: Maxs_hu
from socket import *
import struct
import json
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8000))
while True:
cmd = input('請輸入命令>>>').strip()
if len(cmd) == 0:
break
client.send(cmd.encode("utf8"))
# 1. 先接收表頭長度
header_len = client.recv(4)
header_size = struct.unpack('i', header_len)[0]
# 2. 根據表頭的長度去接收表頭
header = client.recv(header_size)
# 解析表頭資料
header_dic = json.loads(header.decode('utf8'))
print(header_dic)
total_size = header_dic['total_size']
recv_size = 0
data = b''
while recv_size < total_size:
data += client.recv(1024)
recv_size = len(data)
print(data.decode('utf8'))
client.close()
本文來自部落格園,作者:{Max},僅供學習和參考