1. 程式人生 > >粘包現象 粘包解決方案

粘包現象 粘包解決方案

-------------------------------如果事情無法改變,那就改變自己;如果無法說服他人,那就想法說服自己。如果山過不來,那人就過去!

 # ------------------------------------------------------------------------------------------------------------#
 day 28 今日內容
粘包現象:
粘包1:連續的小包,會被優化機制給合併
粘包2:服務端一次性無法完全就收完客戶端傳送的資料,第二再次接收的時候,會接收到第一次遺留的內容

解決粘包的方案:
方案1:先告訴客戶端,資料資訊的長度,然後等客戶端確認之後,再發送真實內容
方案2:通過struct模組,將要傳送的真實資料的長度進行打包,打包成4個位元組,和真實資料一起一次性發送個客戶端.客戶端取出前4個位元組,通過struct解包獲得後面真實資料的長度,根據這個長度再進行資料的接受
合法性連結驗證


明日預習:
Socketserver
# # --------------[粘包方案解決-客戶端]--------------
import json
import socket
import struct
client = socket.socket()
ip_port = ('127.0.0.1',8001)
client.connect(ip_port)
all_recv_len = 0
all_data_byte = b''

while 1:
client_cmd = input('請輸入系統指令>>>')
client.send(client_cmd.encode('utf-8'))
#先接收4個位元組,這4個位元組是真實資料長度加工成的
recv_data_len = client.recv(4)
#將4個位元組長度的資料,解包成後面真實資料的長度
real_data_len = struct.unpack('i',recv_data_len)[0]

print(real_data_len)

server_result = client.recv(real_data_len)

print(server_result.decode('gbk'))
 
# # --------------[粘包方案解決-服務端]--------------
import socket
import subprocess
import struct
server = socket.socket()
ip_port = ('127.0.0.1',8001)
data_full_len = 0 #統計傳送資料的長度
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024).decode('utf-8')

sub_obj = subprocess.Popen(
from_client_cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
#subprocess物件.read 得到的結果是bytes型別的
cmd_res = sub_obj.stdout.read()
data_len = len(cmd_res) #總資料長度
data_len_str = str(data_len)
print('結果長度>>>',data_len)

#將真實資料長度打包成4個位元組的資料
struct_data_len = struct.pack('i',data_len)

conn.send(struct_data_len + cmd_res)


今日作業
1、什麼緩衝區,為什麼會有緩衝區?

2、寫一個tcp寫一下的socket對話程式,能夠優雅的斷開,讓另外一個客戶端連線上進行收發訊息。

3、自行完成今天課上寫的使用subprocess進行系統呼叫的對話方式,客戶端傳送指令,服務端執行指令並且將結果返回給客戶端,確保不產生粘包

4、什麼是粘包? socket 中造成粘包的原因是什麼? 哪些情況會發生粘包現象?

5、用tcp協議下的socket,寫一個簡易的檔案上傳下載的功能,使用者需要登陸認證,認證成功後,客戶端使用者可以選擇上傳或者是下載,
上傳的時候服務端提前設定好上傳檔案的路徑,將檔案上傳到對應的路徑下,下載檔案的時候,服務端將之前設定好的上傳路徑中的所有
檔案帶上序號展示給使用者看,使用者輸入檔案序號後下載對應的檔案,檔案下載到客戶端程式的當前路徑下就可以了。