基於tcp的粘包處理終極版本
阿新 • • 發佈:2018-12-26
為什麼會存在粘包問題?
因為tcp是流失協議 因為接收方不知道傳送方的的資料總量和資料劃分的界限,
解決的思路:
接收方需要先獲取資料的長度
需要傳送方先發送資料的長度給接收方
接收方收到長度之後 按照資料長度來獲取資料
struct 模組
可以將python中的資料型別 轉換成bytes
第一個引數通常是i 其能轉換的資料範圍是c語言的int範圍
如果int不夠 那就用q 表示long long 型
num = 1024
res = struct.pack("i",num) 轉成固定4位的bytes位元組
res2 = struct.unpack("i",res) 從位元組轉回整型
伺服器端 import socket import subprocess import struct import datetime import json server =socket.socket() server.bind(('127.0.0.1',16888)) server.listen() # 要求 不僅返回命令的結果 還要返回執行命令的時間 執行時間:2018/12/26 while True: client,addr = server.accept() while True: try: #接收命令 cmd = client.recv(1024).decode('utf-8') p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) data = p.stdout.read() err_data = p.stderr.read() length = len(data)+len(err_data) #真實資料長度 # 在傳送資料之前傳送額外的資訊 # t = "{執行時間:%s 真實資料長度:%s" % (datetime.datetime.now(),length)# 把要傳送的資料先存到字典中 t ={} t["time"] = str(datetime.datetime.now()) t["size"] = length t["filename"] = "a.mp4" t_json = json.dumps(t) t_data = t_json.encode('utf-8') t_length = struct.pack('i',len(t_data)) client.send(t_length) #1.先發送額外資訊的長度 client.send(t_data) #2.再發送額外資訊 client.send(data) #3.傳送真實資訊 client.send(err_data) except ConnectionResetError: client.close() print('客戶端關閉,連線中斷') break
客戶端 import socket import struct import json c = socket.socket() c.connect(('127.0.0.1',16888)) while True: cmd = input(">>>>>:") if not cmd : print('命令符不能為空') continue c.send(cmd.encode('utf-8')) #接收額外資訊的長度 length = c.recv(4) len_data = struct.unpack('i',length)[0] #接收到的是(72,) 這樣型別的元組 取到長度 72 #接收額外資訊 t_data = c.recv(len_data) json_dic = json.loads(t_data.decode("utf-8")) print('執行時間%s:'%json_dic["time"]) data_size = json_dic["size"] #得到資料長度 #開始接收真實的資料 all_data = b'' #儲存已經接收到的資料 rcv_size = 0 #已經接收長度 while rcv_size < data_size: data = c.recv(1024) rcv_size +=len(data) all_data += data print('接收長度%s'%rcv_size) print(all_data.decode('gbk'))