2010-11-22 94 views
3

我想在一个单线程脚本中有一个交互式控制台,该脚本有多个TCP连接打开。这意味着我不能只有一个标准输入阻塞线程。在单线程Python脚本中有一个控制台

有没有简单的方法来做到这一点?或者我应该把控制台放在它自己的线程中并完成它?

+0

香港专业教育学院最近很多参观这个问题。什么在你看来,你真的描述的是或多或少的一个网络服务器。 那就是我一直在想的 – 2016-10-04 16:38:51

回答

0

单线程或多线程都可以,但是如果您选择不使用线程,您将需要使用轮询(例如,可以使用poll(2)来完成轮询),并检查是否控制台和/或TCP连接已准备就绪。

+0

是的,我得到了那部分。我一直在想方便的方式来以类似控制台的方式读取用户的输入,同时输出内容。就像它已经在图书馆或开源应用程序中完成一样,我可以看看它。 – Blixt 2010-11-22 00:42:10

3

可以继承InteractiveConsole(从内建的“代码”模块)和 与转发到基座 InteractiveConsole的推送()方法之前重定向标准输出/标准错误 到StringIO的实例的包装覆盖push()方法。您的包装可以返回2元组 (更多,结果)其中'more'表示InteractiveConsole是否期望 有更多输入,'result'是InteractiveConsole.push()写入您的StringIO实例的 的任何值。

听起来比它更难。这里的基本前提:

import sys 
from cStringIO import StringIO 
from code import InteractiveConsole 
from contextlib import contextmanager 

__all__ = ['Interpreter'] 


@contextmanager 
def std_redirector(stdin=sys.stdin, stdout=sys.stdin, stderr=sys.stderr): 
    """Temporarily redirect stdin/stdout/stderr""" 

    tmp_fds = stdin, stdout, stderr 
    orig_fds = sys.stdin, sys.stdout, sys.stderr 
    sys.stdin, sys.stdout, sys.stderr = tmp_fds 
    yield 
    sys.stdin, sys.stdout, sys.stderr = orig_fds 


class Interpreter(InteractiveConsole): 
    """Remote-friendly InteractiveConsole subclass 

    This class behaves just like InteractiveConsole, except that it 
    returns all output as a string rather than emitting to stdout/stderr 

    """ 
    banner = ("Python %s\n%s\n" % (sys.version, sys.platform) + 
       'Type "help", "copyright", "credits" or "license" ' 
       'for more information.\n') 

    ps1 = getattr(sys, "ps1", ">>> ") 
    ps2 = getattr(sys, "ps2", "... ") 


    def __init__(self, locals=None): 
     InteractiveConsole.__init__(self, locals=locals) 
     self.output = StringIO() 
     self.output = StringIO() 

    def push(self, command): 
     """Return the result of executing `command` 

     This function temporarily redirects stdout/stderr and then simply 
     forwards to the base class's push() method. It returns a 2-tuple 
     (more, result) where `more` is a boolean indicating whether the 
     interpreter expects more input [similar to the base class push()], and 
     `result` is the captured output (if any) from running `command`. 

     """ 
     self.output.reset() 
     self.output.truncate() 
     with std_redirector(stdout=self.output, stderr=self.output): 
      try: 
       more = InteractiveConsole.push(self, command) 
       result = self.output.getvalue() 
      except (SyntaxError, OverflowError): 
       pass 
      return more, result 

看看这个完整的例子,它从一个UDP套接字接受输入:

启动两个控制台和一个运行server.py, client.py在另一个。 您在client.py中看到的内容应该与python的 常规交互式解释器无法区分,即使所有命令都是 都会往返server.py以进行评估。

当然,使用这样的套接字是非常不安全的,但它说明了如何异步评估外部输入。只要您信任输入源,您的 应该能够适应您的情况。事情变得“有趣”,当有人类型:

while True: continue 

但是,这完全是另外一个问题... :-)

相关问题