tcp協議傳輸中的粘包問題
- 2022 年 7 月 30 日
- 筆記
- 網路編程與高並發編程
什麼是粘包問題
tcp是流體協議. 其nagle演算法會將數據量較小. 並且發送間隔時間較短的多個數據包合併為一個發送. 網路傳輸的時候是一段一段位元組流的發送. 在接收方看來根本不知道位元組流從何開始. 在哪裡結束. 所以粘包問題就是接收方不知道消息之間的界限. 不止到一次性提取多少數據導致的
而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()