在Python中与服务器上的可执行文件交互?

时间:2014-06-27 05:22:26

标签: python subprocess popen

我想在TCP服务器上运行可执行文件,并以交互方式从套接字连接中获取其输入,并将输出发送回客户端,直到可执行文件终止。我正在通过 Popen 子进程进行管道尝试,但它没有帮助与可执行文件的交互(它只需要输入一次但我希望输入全部采用程序退出的时间。)

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

2 个答案:

答案 0 :(得分:1)

以下是使用circuits的实现:

<强> 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()

对于示例会话(此示例已经过全面测试):

玩得开心! :)

注意:我实际上是1 [电路]的开发人员/作者。我认为这是一个很好的例子来写

答案 1 :(得分:1)

只需提供套接字作为子进程的标准输入,输出和错误。 E.g:

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标准的操作系统。