zoukankan      html  css  js  c++  java
  • 粘包现象与解决方案

    粘包

    粘包是指两次输出结果粘到一起,它的发生主要是因为socket缓冲区导致的,粘包只在tcp中产生,不在UDP产生

    粘包的解决方法:

    使用struct模块,先报头长度进行打包发给客户端,客户端收到之后先解包报头长度,再接收真实的数据
    例子:
    服务端:

    #!/usr/bin/env python3
    # -*- coding:utf-8 -*-
    import socket
    import subprocess
    import struct
    import json
    
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',9909)) #0-65535:0-1024给操作系统使用
    phone.listen(5)
    
    print('starting...')
    while True: # 链接循环
        conn,client_addr=phone.accept()
        print(client_addr)
    
        while True: #通信循环
            try:
                #1、收命令
                cmd=conn.recv(8096)
                if not cmd:break #适用于linux操作系统
    
                #2、执行命令,拿到结果
                obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE)
    
                stdout=obj.stdout.read()
                stderr=obj.stderr.read()
    
                #3、把命令的结果返回给客户端
                #第一步:制作固定长度的报头
                header_dic={
                    'filename':'a.txt',
                    'md5':'xxdxxx',
                    'total_size': len(stdout) + len(stderr)
                }
    
                header_json=json.dumps(header_dic)
    
                header_bytes=header_json.encode('utf-8')
    
                #第二步:先发送报头的长度
                conn.send(struct.pack('i',len(header_bytes)))
    
                #第三步:再发报头
                conn.send(header_bytes)
    
                #第四步:再发送真实的数据
                conn.send(stdout)
                conn.send(stderr)
    
            except ConnectionResetError: #适用于windows操作系统
                break
        conn.close()
    
    phone.close()

    客户端:

    #!/usr/bin/env python3
    # -*- coding:utf-8 -*-
    
    import socket
    import struct
    import json
    
    # 产生对象
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 进行连接
    phone.connect(('192.168.43.129',8082))
    while True:
        # 收发消息
        msg = input('>>:').strip()
        if not msg:continue
        phone.send(msg.encode('utf-8'))
        #先收报头长度
        obj = phone.recv(4)
        header_size = struct.unpack('i',obj)[0]
        #接收报头
        header_bytes = phone.recv(header_size)
        #解析对真实数据的描述信息
        header_json = header_bytes.decode('utf-8')
        header_dic = json.loads(header_json)
        total_size = header_dic['total_size']
        #接收真实的数据
        rev_size = 0
        rev_data = b''
        while rev_size < total_size: # 如果接收的数据小于从报头中解析出来的数据会一直循环进行接收
            res = phone.recv(1024)
            rev_data += res
            rev_size += len(res)
        print(rev_data.decode('utf-8'))
    
    phone.close()
  • 相关阅读:
    手动配置linux(centos)的IP地址
    linux(centos)上配置nginx、mysql、phpfpm开机启动
    visual studio 2022 下载地址
    自己动手开发编译器(五)miniSharp语言的词法分析器
    自己动手开发编译器(一)编译器的模块化工程
    自己动手开发编译器(二)正则语言和正则表达式
    趣味问题:你能用Reflection.Emit生成这段代码吗?
    自己动手开发编译器(零)序言
    自己动手开发编译器特别篇——用词法分析器解决背诵圣经问题
    自己动手开发编译器(三)有穷自动机
  • 原文地址:https://www.cnblogs.com/yjiu1990/p/9182840.html
Copyright © 2011-2022 走看看