python--subprocess,粘包现象与解决办法,缓冲区

Posted 截击机1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python--subprocess,粘包现象与解决办法,缓冲区相关的知识,希望对你有一定的参考价值。

一. subprocess 的简单用法

复制代码
import subprocess
sub_obj = subprocess.Popen(
    \'dir\',  #系统指令
    shell=True,  #固定方法
    stdout=subprocess.PIPE, #标准输出  PIPE 管道,保存着指令的执行结果
    stderr=subprocess.PIPE  #标准错误输出
)
# dir 当前操作系统(Windows)的命令,会执行stdout
print(\'正确输出\',sub_obj.stdout.read().decode(\'gbk\'))
# 如果是 \'ls\' 是Linux里的命令 会执行stderr ,因为系统的编码是gbk
print(\'错误输出\',sub_obj.stderr.read().decode(\'gbk\'))
复制代码

二 .两种粘包现象

  1 连续的小包可能会被优化算法给组合到一起进行发送

 

复制代码
# 客户端

import socket
BUFSIZE=1024
ip_port=(\'127.0.0.1\',8080)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# res=s.connect_ex(ip_port)
res=s.connect(ip_port)
# 这边分两段发送
s.send(\'hi\'.encode(\'utf-8\'))
s.send(\'meinv\'.encode(\'utf-8\'))

# 服务端

from socket import *
ip_port=(\'127.0.0.1\',8080)
tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)
conn,addr=tcp_socket_server.accept()
#服务端连接接收两个信息
data1 = conn.recv(10)
data2 = conn.recv(10)
# 如果网络良好的话 收到的应该是 一条信息himeinv
print(\'----->\',data1.decode(\'utf-8\'))
print(\'----->\',data2.decode(\'utf-8\'))
conn.close()
复制代码

 

 

 

 

  2 第一次如果发送的数据大小2000B接收端一次性接受大小为1024,这就导致剩下的内容会被下一次recv接收到,导致结果错乱

 

复制代码
# 客户端

import socket

client = socket.socket()
client.connect((\'127.0.0.1\',8001))
while 1:
    cmd = input(\'请输入指令:\')

    client.send(cmd.encode(\'utf-8\'))
    # 这里写1025是因为粘包的原因需要写1025才能正好接收到完整的字
    server_cmd_result = client.recv(1025)

    print(server_cmd_result.decode(\'gbk\'))


# 服务端

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\'))
    sub_obj = subprocess.Popen(
        from_client_cmd.decode(\'utf-8\'),
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    std_msg = sub_obj.stdout.read()
    print(\'指令的执行结果长度>>>>\',len(std_msg))
    conn.send(std_msg)
复制代码

 

三 . 解决粘包现象的方法

  方案一:由于双方不知道对方发送数据的长度,导致接收的时候,可能接收不全,或者多接收另外一次发送的信息内容,所以在发送真实数据之前,

    要先发送数据的长度,接收端根据长度来接收后面的真实数据,但是双方有一个交互确认的过程.

 

复制代码
# 客户端

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\'))

# 服务端

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)
    #首先将数据长度的数据类型转换为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
复制代码

 

    

  方案二:

    struct模块,

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

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

 

复制代码
# struct 的简单用法
import struct
num = 100
#打包,将int类型的数据打包成4个长度的bytes类型的数据
byt = struct.pack(\'i\',num)
print(byt)  # b\'d\\x00\\x00\\x00\'
#解包,将bytes类型的数据,转换为对应的那个int类型的数据
# int_num = struct.unpack(\'i\',byt)
# print(int_num)  # (100,)
int_num = struct.unpack(\'i\',byt)[0]
print(int_num) # 100
复制代码

 

复制代码
# 客户端

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\'))


# 服务端

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)
复制代码

 

四 . 缓冲区

 

以上是关于python--subprocess,粘包现象与解决办法,缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

Netty进阶——粘包与半包(现象分析)

粘包现象

粘包现象

粘包现象

什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

python3全栈开发-什么是粘包粘包现象如何解决粘包