python 网络编程-03 粘包问题及处理

粘包问题出现在TCP连接下。
由于client 端通过 tcp 连接 向 server端发送消息,多条消息之间没有明显的区分,导致server端在接收时,会将前一条消息的 结尾与下一天消息的开头放入一个缓冲区进行接收。
导致两条数据粘在一起, 称为粘包。

解决粘包的思路为,在发送一条消息时 将前4个字符设置为消息的长度,让接收端知道消息的长度即可区分不同的消息。

粘包问题及解决 / pro.py

import struct


def sender(conn, msg: bytes):
    # 计算消息的长度
    pack_head = struct.pack('i', len(msg))
    # 发送消息的长度
    conn.send(pack_head)
    # 发送消息
    conn.send(msg)


def receiver(conn) -> str:
    # 获取消息的长度
    length = struct.unpack('i', conn.recv(4))[0]
    print(length)
    # 设置缓冲区大小为1024
    buff_size = 1024
    msg = ''
    while True:
        if length < buff_size:
            #  消息长度小于缓冲区大小  接收数据结束循环
            recv_msg = conn.recv(length)
            msg += recv_msg.decode('utf-8')
            break
        else:
            # 消息长度大于缓冲区大小  
            # 接收缓冲区大小的数据
            # 数据长度减去已经接收的长度
            recv_msg = conn.recv(length)
            length -= buff_size
            msg = recv_msg.decode('utf-8')

    return msg

server.py

import socket, subprocess,traceback
from 粘包问题及解决 import proto

if __name__ == '__main__':
    s = socket.socket()
    s.bind(('127.0.0.1', 8000))
    s.listen()
    while True:
        print('等待连接')
        conn, addr = s.accept()
        while True:
            try:
                commend = proto.receiver(conn)
            except Exception as e:
                print('连接异常')
                conn.close()
                print(traceback.print_exc())
                break
            if commend == 'exit':
                conn.close()
                break
            obj = subprocess.Popen(commend, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            out = obj.stdout.read()
            err = obj.stderr.read()
            if err:
                print("err:", err)
                proto.sender(conn, err)
            else:
                print("out", out)
                proto.sender(conn, out)

client.py

import socket
from 粘包问题及解决 import proto

if __name__ == '__main__':
    s = socket.socket()
    s.connect(('127.0.0.1', 8000))
    while True:
        cmd = input("> ")
        proto.sender(s, cmd.encode('utf-8'))
        if cmd == 'exit':
            s.close()
            break
        print(proto.receiver(s))

相关推荐