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)

四 . 缓冲区

原文地址:https://www.cnblogs.com/uiys/p/10673222.html

时间: 2024-07-31 23:53:16

python--subprocess,粘包现象与解决办法,缓冲区的相关文章

python3 tcp的粘包现象和解决办法

服务器端 import socket sk = socket.socket() sk.bind(("127.0.0.1", 6666)) sk.listen() conn, address = sk.accept() def my_send(msg): bs = msg.encode("utf-8") len_str = format(len(bs), "04d") # 定长4位 conn.send(len_str.encode("ut

python学习_day30_基于tcp协议的粘包现象

1.基于远程执行命令的程序 需用到subprocess模块 服务端: #1.执行客户端发送的指令 import socket import subprocess phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind(('127.0.0.1',8090)) phone.listen(5) while True: conn,addr=phone.accept() print('IP:%s PORT:%s' %(addr[0

粘包现象

一.基于udp的套接字 udp是无链接的,先启动哪一端都不会报错 udp服务端: ss = socket() #创建一个服务器的套接字 ss.bind() #绑定服务器套接字 while True : #服务器无限循环 cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送) ss.close() # 关闭服务器套接字 udp客户端: cs = socket() # 创建客户套接字 while True : # 通讯循环 cs.sendto()/cs.recvfrom

基于tcp协议下粘包现象和解决方案

一.缓冲区 每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区.write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器.一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情.TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决

网络编程-之------粘包现象

一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原理 应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因.(因为TCP是流式协议,不知道啥时候开始,啥时候结束).而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提

Python--网络编程-----粘包现象

一.为了防止出现端口占用的情况, linux中可以使用pkill -9 python windows系统中使用taskkill python 二.什么是粘包现象 1.多个包(也就是多个命令的执行结果)粘在一起的现象,叫做粘包现象 2.代码示例如下: 服务端代码: 1 import socket 2 import subprocess 3 4 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 5 # phone.setsockopt

粘包现象(存在于tcp中)

多个包 多个命令的结果 粘到一起了 因为recv(1024)1024限制了导致的结果 所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的. 参考:http://www.cnblogs.com/linhaifeng/articles/6129246.html 粘包底层原理分析: 1.运行一个软件和硬盘.内存.cpu这三个硬件有关 2.启动程序:硬盘程序加载到内存启动一个软件就占一个内存空间 操作系统本身有一个内存空间 操作系统所占得到内存空间和软件的内存空间

20 Apr 18 粘包问题及解决方法

20 Apr 18 一.上节课复习 1. TCP(建立的是一个双向连接)三次握手建连接,四次挥手断连接 三次握手:    c----syn=1 seq=x--->s    s----ack=1+x syn=1 seq=y--->c    c----ack=1+y------->s    四次挥手:    s------fin=1---------->c    c------>ack=1--------->s    c------>fin=1--------->

网络编程基础粘包现象

粘包 tcp是流式传输,字节流,数据与数据之间是没有边界的 流式传输优点: 不限定长度 可靠传输 缺点: 慢 和一个人的通信连接conn会一直占用我们的通信资源 udp协议,面向数据包的传输 数据包优点 快 由于不需要建立连接,所以谁发的消息我都能接受到 缺点 不能传输过长的数据 不可靠 粘包现象 由于流式传输的特点,产生了数据连续发送的粘包现象. 在一个conn建立起来的连接上传输的多条数据是没有边界的 数据的发送和接收实际上不是在执行send/recv的时候就立刻被发送和接收,而是需要经过操