1 ,粘包與拆包 : 發生的時機 ( tcp 協議 )
- 只有 tcp 協議出現粘包現象
- udp 協議是沒有的
2 ,粘包與拆包 : 什麼意思
- 發送端 :發數據
- 接收端 :不知道如何接受
- 後果 : 數據混亂
3 ,混亂 : 代碼
- 服務端 :
# Author:SFL
import socket
import subprocess
sk = socket.socket()
sk.bind(("127.0.0.1",8080))
sk.listen()
conn,addr = sk.accept()
while 1:
cmd = conn.recv(1024).decode("utf-8")
print(cmd)
if cmd=="exit":
break
r = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout = r.stderr.read()
stderr = r.stdout.read()
if stderr:
conn.send(stderr.decode("gbk").encode("utf-8"))
else:
conn.send(stdout.decode("gbk").encode("utf-8"))
conn.close()
sk.close()
- 客戶端 :
# Author:SFL
import socket
import subprocess
sk = socket.socket()
sk.connect_ex(("127.0.0.1",8080))
while 1:
cmd = input(">>>")
sk.send(cmd.encode("utf-8"))
res = sk.recv(1024).decode("utf-8")
if res == "exit":
break
print(res)
sk.close()
4 ,混亂例子 : 操作
- 打開服務端
- 打開客戶端
- 客戶端發送命令 :
1 ,ipconfig
2 ,ls - 現象 : 由於 ipconfig 命令回覆的消息內容較多,導致下一次的命令中,出現了上次應該出現的內容
5 ,混亂 :原因
客戶端的緩衝區大小不夠
6 ,混亂 : 解決
- 思路 : 調整緩衝區大小
- 精華代碼 : 將緩衝區大小變大
res = sk.recv(102400).decode("utf-8")
7 ,粘包 : 經典例子
- 客戶端 :發送數據
發送 hello 和 world :
sk.send(b"hello")
sk.send(b"world")
- 服務端端 : 接收數據
conn.recv(1024)
conn.recv(1024)
- 正常情況 :
hello
world
- 特殊情況 : 粘包
"helloworld"
""
8 ,拆包 :
- MTU :網卡上限 ( 網絡傳輸的最大數據包 )
- 超限拆包 :當 tcp 的緩衝區大於 MTU 上限時,在網絡傳輸中,就會把數據包拆解
9 ,粘包 :
- 根本原因 : 緩衝區大於數據量大小
- 發生的機率 : 不大
- 內部原理 : 一個包,兩條消息
服務端一共就讀到一個數據包,這個數據包包含客戶端發出的兩條消息的完整信息,這個時候基於之前邏輯實現的服務端就蒙了,因爲服務端不知道第一條消息從哪兒結束和第二條消息從哪兒開始,這種情況其實是發生了TCP粘包。
10 ,tcp 與 udp 機制 : 年報比較
- tcp :有可能粘包
- udp:沒可能粘包
11 ,粘包的兩種情況 :
- 發送方緩衝機制 : 發送端需要等緩衝區滿才發送消息,造成粘包
( 請求時間間隔短,每次發送的數據量小 ) - 接收方緩衝機制 : 接收方接收數據不及時,造成多個包被遺棄接收
12 ,粘包,拆包問題的解決方案
- tcp 無界 : tcp是無界的數據流
- 無法從底層解決 : 協議本身無法避免粘包,拆包的發生
- 只能從應用層解決 : 只能在應用層數據協議上,加以控制
- 例如 : 使用帶消息頭的協議、消息頭存儲消息開始標識及消息長度信息,服務端獲取消息頭的時候解析出消息長度,然後向後讀取該長度的內容。
13 ,解決粘包問題的實例 :
- 我的另一篇博客網址 : 文件上傳例子
- https://blog.csdn.net/qq_34319644/article/details/106235226
14 ,緩衝區大小設置多少合適 :
https://my.oschina.net/hejunbinlan/blog/1526871