2014-06-27 44 views
1

我想在TCP服務器上運行可執行文件並交互地從套接字連接中獲取其輸入,並將輸出發送回客戶端,直到可執行文件終止。我是用管道試圖通過它POPEN ,但它不是與可執行的互動幫助(它只是需要輸入只有一次,但我想輸入將要採取的所有時間,直到程序退出)。在Python中與服務器上的可執行文件進行交互?

想我發送「1」輸入到服務器,然後服務器必須發送對應於「1」輸入到客戶端,然後問下一個輸入和做它,直到在延續可執行退出標準輸出。

+0

什麼是可執行文件? –

+0

@James它是一個顯示交互式菜單以供選擇的二進制文件。告訴我任何其他信息,你想知道它不夠? – in3o

+0

你基本上想把這個應用程序包裝到可以連接到的服務器中?你期望在這裏使用什麼樣的客戶?遠程登錄? VT100兼容? –

回答

1

只需提供插座作爲標準輸入,輸出和子進程的錯誤。例如:

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標準的操作系統。

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 [circuits]的開發人員/作者。我認爲這將是寫作的一個很好的例子。

相關問題