在Python中通过服务器与可执行文件交互?

在Python中通过服务器与可执行文件交互?,python,subprocess,popen,Python,Subprocess,Popen,我想在TCP服务器上运行一个可执行文件,以交互方式从套接字连接获取其输入,并将输出发送回客户端,直到可执行文件终止。我曾尝试通过Popen类的子流程进行管道传输,但这无助于与可执行文件的交互(它只接受一次输入,但我希望在程序退出之前一直接受输入) 假设我将“1”输入发送到服务器,那么服务器必须将与“1”输入对应的标准输出发送到客户端,然后请求下一个输入,直到可执行文件继续退出。下面是一个使用: server.py: #!/usr/bin/env python from uuid import

我想在TCP服务器上运行一个可执行文件,以交互方式从套接字连接获取其输入,并将输出发送回客户端,直到可执行文件终止。我曾尝试通过Popen类的子流程进行管道传输,但这无助于与可执行文件的交互(它只接受一次输入,但我希望在程序退出之前一直接受输入)


假设我将“1”输入发送到服务器,那么服务器必须将与“1”输入对应的标准输出发送到客户端,然后请求下一个输入,直到可执行文件继续退出。

下面是一个使用:

server.py

#!/usr/bin/env python


from uuid import uuid4 as uuid
from subprocess import Popen, PIPE


from circuits import handler, Component, Debugger, Event

from circuits.io import File

from circuits.net.sockets import TCPServer
from circuits.net.events import close, write


class kill(Event):
    """kill Event"""


class Command(Component):

    channel = "cmd"

    def __init__(self, sock, command, channel=channel):
        super(Command, self).__init__(channel=channel)

        self._sock = sock
        self._command = command

        self._buffer = None

        self._p = Popen(command, shell=True, stdin=PIPE, stdout=PIPE)

        self._stdin = File(
            self._p.stdin, channel="{0:s}.stdin".format(self.channel)
        ).register(self)

        self._stdout = File(
            self._p.stdout, channel="{0:s}.stdout".format(self.channel)
        ).register(self)

        self.addHandler(
            handler("eof", channel=self._stdout.channel)(self._on_stdout_eof)
        )
        self.addHandler(
            handler("read", channel=self._stdout.channel)(self._on_stdout_read)
        )

    def write(self, data):
        self.fire(write(data), self._stdin.channel)

    def kill(self):
        self._p.terminate()
        self.unregister()

    @staticmethod
    def _on_stdout_eof(self):
        self.fire(kill(), self.channel)
        self.fire(close(self._sock), self.parent.channel)

    @staticmethod
    def _on_stdout_read(self, data):
        self.fire(write(self._sock, data), "server")


class Server(Component):

    channel = "server"

    def init(self, bind, cmd):
        self.cmd = cmd

        self.clients = {}

        TCPServer(bind).register(self)

    def connect(self, sock, host, port):
        command = Command(sock, self.cmd, channel=uuid()).register(self)
        self.clients[sock] = command

    def disconnect(self, sock):
        command = self.clients[sock]
        self.fire(kill(), command.channel)
        del self.clients[sock]

    def read(self, sock, data):
        command = self.clients[sock]
        self.fire(write(data), command.channel)


server = Server(("0.0.0.0", 8000), "python app.py")
Debugger().register(server)

server.run()
app.py:

#!/usr/bin/env python


from __future__ import print_function


import sys


def function1():
    print("I am function 1!")


def function2():
    print("I am function 2!")


def function3():
    raise SystemExit(0)


MENU_OPTIONS = (
    (1, "Function 1"),
    (2, "Function 2"),
    (3, "Function 3")
)


FUNCTIONS = {
    1: function1,
    2: function2,
    3: function3
}


def main():
    while True:
        try:
            print("Menu:")
            for option, description in MENU_OPTIONS:
                print("{0:d}) {1:s}".format(option, description))
            print()
            sys.stdout.flush()

            choice = raw_input("> ")

            try:
                FUNCTIONS[int(choice)]()
            except ValueError:
                print("Invalid Input")
        except (KeyboardInterrupt, EOFError):
            raise SystemExit(0)


if __name__ == "__main__":
    main()
对于示例会话(此示例已经过全面测试):

  • 服务器会话:
  • 客户端会话:
玩得开心!:)


注:我实际上是[circuits]的开发者/作者。我认为这是一个很好的例子。

只需提供套接字作为子流程的标准输入、输出和错误。例如:

import socket
import subprocess

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
listener.bind(('0.0.0.0', 0))
listener.listen(5)
print(listener.getsockname())

try:
    while True:
        client, addr = listener.accept()
        subprocess.Popen(['cat'], stdin=client, stdout=client, stderr=client)
        client.close()
except KeyboardInterrupt:
    pass
finally:
    listener.close()

这可能需要一个兼容POSIX的操作系统。

什么是可执行文件?@James它是一个二进制文件,显示交互式菜单可供选择。告诉我你想知道的其他信息是否还不够?你基本上想把这个应用程序包装成一个可以连接的服务器?您希望在这里使用什么样的客户机?电信网?符合VT100标准吗?我正在linux上使用netcat。好的。我可以为你回答这个问题;然而;答案相当宽泛,可能不适合您的用例。既然是这样,你的问题就太难了。