zoukankan      html  css  js  c++  java
  • 解决粘包

    两种粘包现象
        1 连续的小包可能会被优化算法给组合到一起进行发送
        2 第一层次如果发送的数据大小为2000B,接收端一次性接受大小为1024B,这就导致剩下的内容会被下一次recv接收到,导致混乱
    解决方案一.
        由于双方不知道对方发送数据的长度,导致接收的时候,可能接收不全,或者多接收另外一次
        发送的信息内容,所以在发送真是数据之前,要先发送数据的长度,接收端根据长度来接收后面
        的真实数据。
    import socket
    import subprocess
    server = socket.socket()
    ip_port = ('127.0.0.1',8001)
    server.bind(ip_port)
    server.listen()
    conn,addr = server.accept()
    while 1:
        from_client_cmd = conn.recv(1024)
        print(from_client_cmd.decode('utf-8'))
        #接收到客户端发送来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
        sub_obj = subprocess.Popen(
            from_client_cmd.decode('utf-8'),
            shell=True,
            stdout=subprocess.PIPE,  #正确结果的存放位置
            stderr=subprocess.PIPE   #错误结果的存放位置
        )
        #从管道里面拿出结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
        std_msg = sub_obj.stdout.read()
     
        #为了解决黏包现象,我们统计了一下消息的长度,先将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实数据
        std_msg_len = len(std_msg)
        # std_bytes_len = bytes(str(len(std_msg)),encoding='utf-8')
        #首先将数据长度的数据类型转换为bytes类型
        std_bytes_len = str(len(std_msg)).encode('utf-8')
        print('指令的执行结果长度>>>>',len(std_msg))
        conn.send(std_bytes_len)
     
        status = conn.recv(1024)
        if status.decode('utf-8') == 'ok':
            conn.send(std_msg)
        else:
            pass
    View Code
    import socket
     
    client = socket.socket()
    client.connect(('127.0.0.1',8001))
    while 1:
        cmd = input('请输入指令:')
        client.send(cmd.encode('utf-8'))
        server_res_len = client.recv(1024).decode('utf-8')
        print('来自服务端的消息长度',server_res_len)
        client.send(b'ok')
        server_cmd_result = client.recv(int(server_res_len))
        print(server_cmd_result.decode('gbk'))
    View Code
    解决方案二:使用struct模块处理数据长度,再将发送的数据长度和内容整合在一起发送
        struct模块封装的int类型为4个字节,所以可以直接在接收时先定下长度.
        打包:struct.pack('i',长度)
        解包:struct.unpack('i',字节流)
    

      

    import socket
    import subprocess
    import struct
    server = socket.socket()
    ip_port = ('127.0.0.1',8001)
    server.bind(ip_port)
    server.listen()
    conn,addr = server.accept()
     
    while 1:
        from_client_cmd = conn.recv(1024)
     
        print(from_client_cmd.decode('utf-8'))
        #接收到客户端发送来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
        sub_obj = subprocess.Popen(
            from_client_cmd.decode('utf-8'),
            shell=True,
            stdout=subprocess.PIPE,  #正确结果的存放位置
            stderr=subprocess.PIPE   #错误结果的存放位置
        )
        #从管道里面拿出结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
        std_msg = sub_obj.stdout.read()
     
        #为了解决黏包现象,我们统计了一下消息的长度,先将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实数据
        std_msg_len = len(std_msg)
     
        print('指令的执行结果长度>>>>',len(std_msg))
     
        msg_lenint_struct = struct.pack('i',std_msg_len)
        conn.send(msg_lenint_struct+std_msg) 
    View Code
    import socket
    import struct
    client = socket.socket()
    client.connect(('127.0.0.1',8001))
     
    while 1:
        cmd = input('请输入指令:')
        #发送指令
        client.send(cmd.encode('utf-8'))
     
        #接收数据长度,首先接收4个字节长度的数据,因为这个4个字节是长度
        server_res_len = client.recv(4)
        msg_len = struct.unpack('i',server_res_len)[0]
     
        print('来自服务端的消息长度',msg_len)
        #通过解包出来的长度,来接收后面的真实数据
        server_cmd_result = client.recv(msg_len)
     
        print(server_cmd_result.decode('gbk'))
    View Code
  • 相关阅读:
    如何从零开始创建一个IT信息系统
    Linux常用命令
    vue.js 3.2.20: 用rem实现移动端和pc的兼容
    vue.js3.2.6:路由处理404报错(vue-router@4.0.11)
    vue.js项目在nginx上部署:使spring后端记录真实ip地址
    vue.js 3.0.5:用vue-i18n开发i18n国际化功能(vue-i18n@9.2.0)
    前台项目基础框架之spring boot后端(spring boot v2.5.4)
    前台项目基础框架之vue前端(vue@3.2.6)
    intellij idea 2021.2:为一个spring boot项目改名
    git:修改项目的remote地址(git version 2.30.2)
  • 原文地址:https://www.cnblogs.com/topass123/p/12817881.html
Copyright © 2011-2022 走看看