粘包问题解决

 send和recv

一个send可以对应多个recv

# 服务端:
import socket

server = socket.socket()
server.bind(('127.0.0.1',9045))
server.listen(5)
conn,addr = server.accept()
print(conn.recv(10))
print(conn.recv(10))
print(conn.recv(10))
print(conn.recv(10))
print(conn.recv(10))
print(conn.recv(10))        #在数据取完了之后再recv的数据是空
conn.close()
server.close()

# 客户端:
import socket

client = socket.socket()
client.connect(('127.0.0.1',9045))
client.send(b'sfaugsdaifjaskdbvziwadF')
client.close()

# 结果:
b'sfaugsdaif'
b'jaskdbvziw'
b'adF'
b''
b''
b''

一个recv可以对应多个send

 

# 服务端:
import socket

server = socket.socket()
server.bind(('127.0.0.1',9045))
server.listen(5)
conn,addr = server.accept()
print(conn.recv(1024))     # send多次发送少量数据,一次打印出来
conn.close()
server.close()

# 客户端:
import socket

client = socket.socket()
client.connect(('127.0.0.1',9045))
client.send(b'sfa')
client.send(b'as')
client.send(b'iwa')
client.send(b'tf')
client.close()


# 结果:
b'sfaasiwatf'

总结:

1.send和recv不是必须要一一对应的

2.只要通道不关闭的状态下,而且客户端不给服务端发数据,服务端就会一直处于recv状态

粘包问题解决

 low版

 

# 服务端:
import socket
import subprocess
import struct

server = socket.socket()
server.bind(('127.0.0.1',8848))
server.listen(5)
while 1:
    conn,addr = server.accept()
    while 1:
        try:
            cmd = conn.recv(1024).decode('utf-8')
            obj = subprocess.Popen(cmd,
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            right_msg = obj.stdout.read()
            error_msg = obj.stderr.read()
            # 获取数据总长度
            total_data_size = len(right_msg + error_msg)
            print(total_data_size)
            # 将总长度转化成固定长度的字节
            total_data_size_bytes = struct.pack('i',total_data_size)    #无论总长度是几位,转化后长度都是4
            # 发送总长度字节和总数据
            conn.send(total_data_size_bytes)
            conn.send(right_msg + error_msg)
        except Exception:
            break
    conn.close()
server.close()


# 客户端:
import socket
import struct

client = socket.socket()
client.connect(('127.0.0.1',8848))
while 1:
    cmd = input('>>>').strip()
    client.send(cmd.encode('utf-8'))
    # 接收固定长度
    head_bytes = client.recv(4)
    # 将head_bytes还原成int类型
    total_data_len = struct.unpack('i',head_bytes)[0]   # unpack转化之后是元祖的形式,用下标将int取出来
    print('长度:',total_data_len)
    # 循环接收所有的数据
    total_data = b''
    while len(total_data) < total_data_len:
        data = client.recv(1024)
        total_data += data
    print(total_data.decode('gbk'))
client.close()

 

缺点:

1.数据如果过大,struct就会报错

2.如果上传下载文件(视频,音频,文件等),需要自定义报头(文件名,路径,大小,md5值等)

高端版

# 服务端:
import socket
import subprocess
import struct
import json

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

while 1:
    conn, addr = server.accept()
    while 1:
        try:
            cmd = conn.recv(1024).decode('utf-8')
            obj = subprocess.Popen(
                cmd,
                shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            right_msg = obj.stdout.read()
            error_msg = obj.stderr.read()

            # 1, 自定制报头
            head_dic = {
                'file_name': 'xx.mp4',
                'file_path': r'C:\Users\oldboy\PycharmProjects\s19\day30\04 recv的问题\server.py',
                'file_size': len(error_msg + right_msg),
            }
            # 2,将head_dic利用json转化成json字符串
            head_dic_json = json.dumps(head_dic)

            # 3,将json字符串转化成bytes
            head_dic_json_bytes = head_dic_json.encode('utf-8')

            # 4,利用strcut将head_dic_json_bytes转化成固定的4个字节
            head_dic_json_bytes_struct = struct.pack('i',len(head_dic_json_bytes))  # 内容bytes长度固定的4个字节
            # print(head_dic_json_bytes_struct,len(head_dic_json_bytes_struct))

            # 5,发送固定4个字节
            conn.send(head_dic_json_bytes_struct)

            # 6,发送bytes类型的字典的报头数据head_dic_json_bytes
            conn.send(head_dic_json_bytes)

            # 7, 发送总数据
            conn.send(right_msg + error_msg)
        except Exception:
            break
    conn.close()
server.close()


# 客户端:
import socket
import struct
import json

client = socket.socket()
client.connect(('127.0.0.1',8888))
while 1 :
    cmd = input('>>>').strip()
    client.send(cmd.encode('utf-8'))

    # 1,接受4个字节
    head_dic_json_bytes_size_strcut = client.recv(4)

    # 2,利用struct反解出head_dic_json_bytes的具体size
    head_dic_json_bytes_size = struct.unpack('i',head_dic_json_bytes_size_strcut)[0]

    # 3,接受head_dic_json_bytes具体数据
    head_dic_json_bytes = client.recv(head_dic_json_bytes_size)

    # 4,将head_dic_json_bytes转化成json的格式
    head_dic_json = head_dic_json_bytes.decode('utf-8')

    # 5, head_dic_json 反序列化成字典类型
    head_dic = json.loads(head_dic_json)

    # 6 循环接收数据
    total_data = b''
    while len(total_data) < head_dic['file_size']:
        total_data += client.recv(1024)
    print(total_data.decode('gbk'))
client.close()

 

posted @ 2019-02-22 21:12  Sandy-123  阅读(203)  评论(0编辑  收藏  举报