• day28 黏包及黏包解决方案


    今日主要内容: 

    一 .缓冲区 

    二.两种黏包现象

    三.黏包现象的两种解决方案

    四.打印进度条(补充的,了解即可)

    1. 缓冲区

    缓冲区的作用 : 将程序和网络解耦(这样做的好处是程序不会以为网速的快慢而影响程序的发送)

    缓冲区分为输入缓冲区和输出缓冲区(在客户端和服务端都存在缓冲区)

    import subprocess
        sub_obj=subprocess.Popen(
        '你输入的指令',  # 这里放的是你输入的指令
        shell=True,   # 固定格式
        stdout=subprocess.PIPE,  # 正确结果的存放位置
        stderr=subprocess.PIPE   # 错误结果的存放位置
      )
    

    2.两种黏包现象 

      1) 两个连续小包传输,因为网速过快的缘故可能会被优化算法给组合到一起进行发送

      2) 两个数据比较大的包(比如2个2000B的)传输,接收端一次性接收数据的大小 小于包的大小(比如一次性接收最大1024B),这样就会导致剩下的数据(976B)会在下一次开头接收,导致下一次的数据结果混乱.

    3. 黏包现象的两种解决方案

    方案1: 由于双方不知道发送的数据的大小长度,才导致黏包现象,因此我们要在发送真实数据之前,先把发送数据的具体长度发送给对方,接收端可以根据接收到的数据长度来接收下面的真实数据(这样会比较麻烦,因为在每次发送数据之前都要发送具体的数据长度,多了一个交互确认的功能).

    方案1:

    首先我们看一下服务端的具体代码:

    # 黏包现象解决方案1 服务端
    import socket
    import subprocess
    sever=socket.socket()
    ip_port=('127.0.0.1',8008)
    sever.bind(ip_port)
    sever.listen()
    conn,addr=sever.accept()
    while 1:
        from_client_msg=conn.recv(1024)
        print(from_client_msg.decode('utf-8'))
        #接收到客户端发来的指令后,服务端先通过subprocess模块找到服务端系统,然后执行这个命令
        sub_obj=subprocess.Popen(
        from_client_msg.decode('utf-8'),
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
        )
        #从管道中拿到sudout正确的结果,通过Popen实例化对象,read()获取结果
        std_msg=sub_obj.stdout.read()
        #为了解决黏包的现象,我们先统计消息的长度,先发送消息的长度,在发送真实的数据
        std_len_msg=len(std_msg)
        #转化成字节长度
        std_len_bytes=bytes(str(std_len_msg)).encode('utf-8')
        # 看一下长度
        print('指令执行结果长度>>>>>',std_len_msg)
        conn.send(std_len_bytes)
        #接收数据
        msg=conn.recv(1024)
        # 发送真实数据
        conn.send(std_msg)   
    

      

    下面我们来看一下客户端的代码

    import socket
    client=socket.socket()
    ip_port=('127.0.0.1',8008)
    client.connect(ip_port)
    while 1:
        to_msg=input('请输入你的指令:')
        # 向服务端发送你的指令
        client.send(to_msg.encode('utf-8'))
        # 服务端第一次发送的是数据的长度(长度是bytes类型)
        from_sever_len=client.recv(1024).decode('utf-8')
        # 客户端接收数据按照服务端给的长度来接收
        client_result=client.recv(int(from_sever_len))
        print(client.result.decode('gbk'))
    

      

    到这里解决黏包现象的第一种方案已经写完了,下面要介绍第二种解决黏包现象的方案  

    方案2:

    这里的方案2需要用到的是struct模块

    import struct

    打包: struct.pack('i',长度)

    解包: struct.unpack('i',字节)

    老样子,服务端的代码

    import socket
    import subprocess
    import struct
    sever=socket.socket()
    ip_port=('127.0.0.1',8008)
    sever.bind(ip_port)
    sever.listen()
    conn,addr=sever.accept()
    while 1:
        from_client_msg=conn.crev(1024)
        print(from_client_msg.decode('utf-8'))
        # 和第一种一样,接收客户端的指令,先在服务端通过subprocess模块到系统里执行
        sub_obj=subprocess.Popen(
        from_client_msg.decode('utf-8'),
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
        )
        #从管道中拿到正确的stdout,通过read()方法或取管道中的结果
        sub_result=sub_obj.sudout.read()
        #为了解决黏包现象,我们先统计数据的长度,现将长度发送给客户端,
      客户端通过长度来接受我们后面要发送的真实的数据.
        sub_obj_len=len(sub_result)
        # 打印一下长度
        print('指令的执行结果长度',sub_obj_len)
        #以下数据就是跟第一种方法的区别
        msg_lenint=struct.pack('i',sub_obj_len)
        # 将长度和数据一起发送出去(拼接)
        conn.send(msg_lenint+sub_result)
    

      

    下面是客户端的代码

    import socket
    import struct
    client=socket.socket()
    ip_port=('127.0.0.1',8008)
    client.connect(ip_port)
    while 1:
        client_msg=input('请输入你的指令:')
        client.send(client_msg.encode('utf-8'))
        #先接受4个字节,这4个字节是服务端发送的长度
        from_sever_msg=client.recv(4)
        #解包,解包后的结果为(xx,)元组,我们要拿到xx,直接[0]即可.此时拿到的就是数据的长度
        msg_len=struct.unpack('i',from_sever_len)[0]
        #拿到数据
        from_client_rst=client.recv(msg_len)
        #打印结果
        print(from_client_rst.decode('gbk'))
    

      

    4.打印进度条(补充的,了解即可)

    import time

    for i in range(20):

      print(' ' + " * " * i,end=' ') # 的作用是每次打印从头开始打印

      time.sleep(3)

  • 相关阅读:
    PHP mysqli 扩展库(面向对象/数据库操作封装/事务控制/预编译)
    php 下载文件的函数
    PBOC电子钱包与电子现金及QPBOC
    基于PBOC电子钱包的消费过程详解
    PBOC规范下的java卡介绍
    基于PBOC电子钱包的圈存过程详解
    电子钱包和电子现金的区别
    DES,3DES,AES这三种对称密钥的区别与联系
    密钥体系
    关于卡片的主控密钥和应用主控密钥
  • 原文地址:https://www.cnblogs.com/zty1304368100/p/10225379.html
Copyright © 2020-2023  润新知