• 黏包


    黏包现象

    同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种现象就是黏包。只有TCP协议会有黏包现象,UDP协议永远不会黏包

    形成原因

    原因一

    在发送端,由于两条信息发送的间隔时间很短,且两条消息本身也很短,在发送之前被合并成一条信息

    根据三次握手机制,发送方和接收方需要连续互相发送信息

    而为了节省内存,减少互相发送信息次数

    所以可能会直接把两条消息打包成一条发送给了接收方

    造成了黏包现象

    原因二

    在接收端,由于接收不及时导致两条先后到达的信息在接收端黏在了一起

    发送方发送信息后,接收端可能正在运行其他代码

    在接收端可能会把收到的第一条信息先放下

    在处理完后,会把放下的一二条信息同时打印出来

    本质

    信息与信息之间没有边界

    这个现象是没有办法打破的

    因为TCP协议是一种流式传输

    解决方法

    利用struct模块

    struct模块可以把 +- 2147483647之间的数字转为4个字节

    自定义协议

    低级

    import struct
    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',9001))
    sk.listen()
    
    conn,addr = sk.accept()
    str_msg = 'hello,你好么'
    byets_msg = str_msg.encode('utf-8')
    num = len(byets_msg)
    len_bytes = struct.pack('i',num)
    conn.send(len_bytes)
    conn.send(byets_msg)
    conn.send(b'world')
    conn.close()
    
    sk.close()
    server端
    import time
    import struct
    import socket
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',9001))
    
    time.sleep(0.1)
    num= sk.recv(4)
    num = struct.unpack('i',num)[0]
    msg2 = sk.recv(num)
    print(msg2.decode('utf-8'))
    print(sk.recv(1024))
    
    sk.close()
    client端

    高级

      

    import json
    import struct
    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',9001))
    sk.listen()
    
    conn,addr = sk.accept()
    num = conn.recv(4)
    num = struct.unpack('i',num)[0]
    str_dic = conn.recv(num).decode('utf-8')
    dic = json.loads(str_dic)
    with open(dic['filename'],'wb') as f:
        content = conn.recv(dic['filesize'])
        f.write(content)
    
    conn.close()
    sk.close()
    server端
    import os
    import json
    import struct
    import socket
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',9001))
    
    filepath  = input('请输入文件路径 :')
    filename = os.path.basename(filepath)
    filesize = os.path.getsize(filepath)
    dic = {'filename':filename,'filesize':filesize}
    str_dic = json.dumps(dic)
    bytes_dic = str_dic.encode('utf-8')
    len_dic = len(bytes_dic)
    bytes_len = struct.pack('i',len_dic)
    sk.send(bytes_len)
    sk.send(bytes_dic)
    with open(filepath,'rb') as f:
        content = f.read()
        sk.send(content)
    sk.close()
    client端
    旗舰版
    import socket
    import subprocess
    import struct
    import json
    phone = socket.socket()
    
    phone.bind(('127.0.0.1', 8888))
    
    phone.listen(5)
    
    print('start')
    conn, addr = phone.accept()
    while 1:
        try:
            cmd = conn.recv(1024)
            obj = subprocess.Popen(cmd.decode('utf-8'),
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   )
    
            result = obj.stdout.read() + obj.stderr.read()
            result = result.decode('gbk').encode('utf-8')
            # print(f'服务端发送的总字节数{len(result)}')
    
            # 1. 制作报头
    
            head_dict = {
                'MD5': 'fdsaf2345544324dfs',
                'file_name': '婚前视频',
                'file_size': len(result),
            }
    
            # 2. 将报头字典转化成json字符串
            head_dict_json = json.dumps(head_dict)
    
            # 3. 将json字符串 转化成bytes
            head_dict_json_bytes = head_dict_json.encode('utf-8')
    
            # 4. 获取报头的长度
            head_len = len(head_dict_json_bytes)
    
            # 5.将长度转化成固定的4个字节
            head_len_bytes = struct.pack('i',head_len)
    
            # 6. 发送固定的4个字节
            conn.send(head_len_bytes)
    
            # 7. 发送报头
            conn.send(head_dict_json_bytes)
    
            # 8. 发送原数据
            conn.send(result)
    
        except ConnectionResetError:
            break
    conn.close()
    phone.close()
    server端
    import json
    import struct
    import socket
    
    phone = socket.socket()
    phone.connect(('127.0.0.1',9799))
    
    while 1:
        send_msg = input('>>>')
        phone.send(send_msg.encode('utf-8'))
        bytes_msg = phone.recv(4)
        len_msg = struct.unpack('i',bytes_msg)[0]
        s = b''
        while len(s) < len_msg:
            s += phone.recv(1024)
        # dic = json.loads(s)['result']
        dic = json.loads(s.decode('utf-8'))['result']
    
        print(dic)
    
    phone.close()
    client端
  • 相关阅读:
    接口
    多态
    封装
    初识继承
    对象的行为
    类、对象、包
    Java方法
    winform 报表的基本使用
    oracle配合C#的使用
    sql面试语句与后台调用js提示语句
  • 原文地址:https://www.cnblogs.com/biulo/p/10684621.html
Copyright © 2020-2023  润新知