網絡編程-08TCP粘包問題以及解決方案

一丶什麼是粘包

會將數據量比較小的而且時間間隔比較短的數據
一次性打包發送給對方什麼是粘包python

阿攀大白話:

上次或者前面的數據沒發收完,致使以後的影響了以後的獲取數據這種現象shell

二丶粘包產生緣由

  1. 將數據量比較小的而且時間間隔比較短的數據json

  2. 一次性打包發送給對方,對方沒接收完緩存

三丶粘包代碼舉例

3.1服務端socket

import socket, subprocess

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.bind(('127.0.0.1', 8000))
server.listen(5)

while True:
    conn, addr = server.accept()

    print('start...')
    while True:
        cmd = conn.recv(1024)
        print('cmd:', cmd)

        obj = subprocess.Popen(cmd.decode('utf8'),
                               shell=True,
                               stderr=subprocess.PIPE,
                               stdout=subprocess.PIPE)

        stdout = obj.stdout.read()

        if stdout:
            ret = stdout
        else:
            stderr = obj.stderr.read()
            ret = stderr

        ret_len = len(ret)

        conn.send(str(ret_len).encode('utf8'))

        data = conn.recv(1024).decode('utf8')

        if data == 'recv_ready':
            conn.sendall(ret)

    conn.close()

server.close()

3.2客戶端code

import socket


client = socket.socket()  # 拿電話
client.connect(('127.0.0.1',8080))  # 撥號   寫的是對方的ip和port

client.send(str(1).encode("utf-8"))
# client.send(b'hello')
# client.send(b'world')
# client.send(b'baby')

struct模塊解決粘包

直入主題,最好的解決方法:使用struct模塊建立報頭server

解決粘包問題的核心就是:爲字節流加上自定義固定長度報頭,報頭中包含字節流長度,而後一次send到對端,對端在接收時,先從緩存中取出定長的報頭,而後再取真實數據。索引

解決粘包問題
服務端
1.先製做一個發送給客戶端的字典
2.製做字典的報頭
3.發送字典的報頭
4.發送字典
5.再發真實數據ip

客戶端
1.先接受字典的報頭
2.解析拿到字典的數據長度
3.接受字典
4.從字典中獲取真實數據的長度
5.接受真實數據utf-8

4.1服務端

import socket
import subprocess
import struct
import json


server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)


while True:
    conn, addr = server.accept()
    while True:
        try:
            cmd = conn.recv(1024)
            if len(cmd) == 0:break
            cmd = cmd.decode('utf-8')
            obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            res = obj.stdout.read() + obj.stderr.read()
            d = {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'}
            json_d = json.dumps(d)
            # 1.先製做一個字典的報頭
            header = struct.pack('i',len(json_d))
            print(type(header), header ,'12345678')
            # 2.發送字典報頭
            conn.send(header)
            # 3.發送字典
            conn.send(json_d.encode('utf-8'))
            # 4.再發真實數據
            conn.send(res)
            # conn.send(obj.stdout.read())
            # conn.send(obj.stderr.read())
        except ConnectionResetError:
            break
    conn.close()

4.2客戶端

import socket
import struct
import json

client = socket.socket()
client.connect(('127.0.0.1',8080))

while True:
    msg = input('>>>:').encode('utf-8')
    if len(msg) == 0:continue
    client.send(msg)
    # 1.先接受字典報頭
    header_dict = client.recv(4)
    # 2.解析報頭 獲取字典的長度
    dict_size = struct.unpack('i',header_dict)[0]  # 解包的時候必定要加上索引0
    # 3.接收字典數據
    dict_bytes = client.recv(dict_size)
    dict_json = json.loads(dict_bytes.decode('utf-8'))
    # 4.從字典中獲取信息
    print(dict_json)
    recv_size = 0
    real_data = b''
    while recv_size < dict_json.get('file_size'):  # real_size = 102400
        data = client.recv(1024)
        real_data += data
        recv_size += len(data)
    print(real_data.decode('gbk'))


"""
1.如何將對方發送的數據收乾淨

"""
相關文章
相關標籤/搜索