Python 'socketserver' 只处理第一个请求

Python 'socketserver' only ever handles the first request

客户端输出

为了说明问题,这里是 运行 在客户端上运行时的代码。可以看出,第一个命令成功(它总是成功)并且即使在错误命令的情况下它也会成功 return stderr.

Pwny ~>df
Filesystem     1K-blocks     Used Available Use% Mounted on
udev             1895788        0   1895788   0% /dev
tmpfs             386392     1416    384976   1% /run
/dev/sda1      478612200 43470808 410755756  10% /
tmpfs            1931948    78200   1853748   5% /dev/shm
tmpfs               5120        0      5120   0% /run/lock
tmpfs             386388       60    386328   1% /run/user/1000

Pwny ~>pwd

Pwny ~>pwd
[~] Connection aborted
Pwny ~>

服务器输出

这是我服务器的输出。

└─$ /bin/python3 /home/user/Desktop/tcpserver/socketserver.py
[*] Started server 0.0.0.0:9999
[*] 192.168.137.1:1051 connected
[~] 192.168.137.1:1051 df

TCP 客户端程序

这是我的客户端代码:

import socket

class TCPClient:
    @staticmethod
    def run(host, port, buffer_size=1024, encoding='utf-8'):
        HOST = host
        PORT = port
        BUFFER_SIZE = buffer_size
        ENCODING = encoding
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect((HOST, PORT))
            while True:
                tx: bytes = bytes(input("Pwny ~>"), ENCODING)
                tx += b"\n"
                if tx == b"exit":
                    break
                else:
                    try:
                        s.sendall(tx)
                        full_msg: bytes = b''
                        while True:
                            msg: bytes = s.recv(BUFFER_SIZE)
                            if len(msg) == 0:
                                break
                            full_msg += msg
                        print(full_msg.decode(ENCODING))
                    except ConnectionAbortedError:
                        print("[~] Connection aborted")
                    except OSError:
                        print("[~] An OS error occurred")


if __name__ == '__main__':
    tcp_client = TCPClient()
    tcp_client.run(host='192.168.137.2', port=9999, buffer_size=128, encoding='utf-8')

TCP SocketServer程序

这是socketserver程序(我怀疑我在这里做某事,非常感谢帮助)

import socketserver
import subprocess
from subprocess import CompletedProcess

class ThreadingServer(socketserver.ThreadingMixIn,socketserver.TCPServer): pass

class TCPRequestHandler(socketserver.StreamRequestHandler):
    def setup(self) -> None:
        return super().setup()

    def handle(self) -> None:
        ENCODING: str = 'utf-8'
        BUFFER_SIZE: int = 128
        client_address: str = self.request.getpeername()[0]
        client_port: int = self.request.getpeername()[1]

        print(f"[*] {client_address}:{client_port} connected")

        client_cmd: str = self.rfile.readline().decode(ENCODING).strip()
        print(f"[~] {client_address}:{client_port} {client_cmd}")
        output: CompletedProcess = subprocess.run(client_cmd,shell=True,capture_output=True)
        """ Returns 0 for success and >= 1 for failure"""
        if output.returncode == 0: # success
            self.wfile.write(output.stdout)
        else: # failure when > 0
            self.wfile.write(output.stderr)

    def finish(self) -> None:
        return super().finish()

if __name__ == '__main__':
    with ThreadingServer(('0.0.0.0',9999),TCPRequestHandler) as server:
        print(f"[*] Started server {server.server_address[0]}:{server.server_address[1]}")
        server.serve_forever()

您的客户端和服务器都有问题。

客户端使用套接字.recv()读取数据,但是当服务器输出完成时,这将在第一个命令结束时永远阻塞。它会 return b'' 只有在 EOF,当套接字被服务器关闭时。由于服务器问题(如下),它似乎可以工作。

您的服务器代码仅读取一行,生成命令,发送输出,然后 returns 超出 handle(),之后连接关闭。由于这个关闭,客户端实际工作(它从 recv() 获得 b'')。

要修复服务器,请在循环中执行 readline() 直到它 returns b''(客户端关闭套接字)并且最好 flush() 发送后的写入流命令输出。

示例服务器处理程序:

    def handle(self) -> None:
        ENCODING: str = 'utf-8'
        BUFFER_SIZE: int = 128
        client_address: str = self.request.getpeername()[0]
        client_port: int = self.request.getpeername()[1]

        print(f"[*] {client_address}:{client_port} connected")

        while True:
            line: str = self.rfile.readline()
            if line == b'':
                break
            client_cmd: str = line.decode(ENCODING).strip()
            print(f"[~] {client_address}:{client_port} {client_cmd}")
            output: CompletedProcess = subprocess.run(client_cmd,shell=True,capture_output=True)
            """ Returns 0 for success and >= 1 for failure"""
            if output.returncode == 0: # success
                self.wfile.write(output.stdout)
            else: # failure when > 0
                self.wfile.write(output.stderr)
            self.wfile.flush()

要修复客户端和整个设置,您可能需要实施某种框架,对于客户端命令,这当前是一个换行符(因为您使用了 readline),但对于服务器输出,您需要找出一个单独取景。