1. 程式人生 > >基於tcp的粘包處理終極版本

基於tcp的粘包處理終極版本

為什麼會存在粘包問題?

因為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'))