黏包解決方案

解決方案

# 咱們能夠藉助一個模塊,這個模塊能夠把要發送的數據長度轉換成固定長度的字節。這樣客戶端每次接
# 收消息以前只要先接受這個固定長度字節的內容看一看接下來要接收的信息大小,那麼最終接受的數據
# 要達到這個值就中止,就能恰好很少很多的接收完整的數據了。

# import json,struct
# #假設經過客戶端上傳1T:1073741824000的文件a.txt

# #爲避免粘包,必須自定製報頭
# header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'} #1T數據,文件路徑和md5值

# #爲了該報頭能傳送,須要序列化而且轉爲bytes
# head_bytes=bytes(json.dumps(header),encoding='utf-8') #序列化並轉成bytes,用於傳輸

# #爲了讓客戶端知道報頭的長度,用struck將報頭長度這個數字轉成固定長度:4個字節
# head_len_bytes=struct.pack('i',len(head_bytes)) #這4個字節裏只包含了一個數字,該數字是報頭的長度

# #客戶端開始發送
# conn.send(head_len_bytes) #先發報頭的長度,4個bytes
# conn.send(head_bytes) #再發報頭的字節格式
# conn.sendall(文件內容) #而後發真實內容的字節格式

# #服務端開始接收
# head_len_bytes=s.recv(4) #先收報頭4個bytes,獲得報頭長度的字節格式
# x=struct.unpack('i',head_len_bytes)[0] #提取報頭的長度

# head_bytes=s.recv(x) #按照報頭長度x,收取報頭的bytes格式
# header=json.loads(json.dumps(header)) #提取報頭

# #最後根據報頭的內容提取真實的數據,好比
# real_data_len=s.recv(header['file_size'])
# s.recv(real_data_len)


# 咱們還能夠把報頭作成字典,字典裏包含將要發送的真實數據的詳細信息,而後json序列化,
# 而後用struck將序列化後的數據長度打包成4個字節(4個本身足夠用了)

#     發送時                            接收時
# 先發報頭的長度             先收報頭長度,用struct取出來
# 再編碼報頭內容而後發送        根據取出的長度收取報頭內容,而後解碼,反序列化
# 最後發真實內容            從反序列化的結果中取出待取數據的詳細信息,而後去取真實的數據內容

#例子:
#server端
import socket, struct, json
import subprocess

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 就是它,在bind前加

phone.bind(('127.0.0.1', 8080))

phone.listen(5)

while True:
    conn, addr = phone.accept()
    while True:
        cmd = conn.recv(1024)
        if not cmd: break
        print('cmd: %s' % cmd)

        res = subprocess.Popen(cmd.decode('utf-8'),
                               shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
        err = res.stderr.read()
        print(err)
        if err:
            back_msg = err
        else:
            back_msg = res.stdout.read()

        conn.send(struct.pack('i', len(back_msg)))  # 先發back_msg的長度
        conn.sendall(back_msg)  # 在發真實的內容

    conn.close()


#client端
import socket, struct

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
res = s.connect_ex(('127.0.0.1', 8080))

while True:
    msg = input('>>: ').strip()
    if len(msg) == 0: continue
    if msg == 'quit': break

    s.send(msg.encode('utf-8'))

    l = s.recv(4)
    x = struct.unpack('i', l)[0]
    print(type(x), x)
    # print(struct.unpack('I',l))
    r_s = 0
    data = b''
    while r_s < x:
        r_d = s.recv(1024)
        data += r_d
        r_s += len(r_d)

    print(data.decode('utf-8'))
    # print(data.decode('gbk')) #windows默認gbk編碼
相關文章
相關標籤/搜索