2012-05-15 5 views
3

Я написал простой tcp-сервер, используя gevent.StreamServer для тестирования. Чтобы отправлять ответы некоторым клиентам, мне нужен неблокирующий способ обработки ввода через raw_input(), предпочтительно без использования потоков.gevent.StreamServer и неблокирование raw_input()?

Через некоторое Googling я наткнулся этот вопрос: How to make non-blocking raw_input when using eventlet.monkey_patch() and why it block everything, even when executed on another thread?

Я написал следующее, и это именно то, что я хочу, однако я предполагаю, что есть лучший подход к нему. Может ли кто-нибудь указать мне в правильном направлении? Также оценивается идея, почему try/except не поймает KeyboardInterrupt.

import select 
from gevent.monkey import patch_all 
from gevent.server import StreamServer 

patch_all(os=True, select=True) 

def raw_input(message): 
    """ Non-blocking input from stdin. """ 
    sys.stdout.write(message) 

    select.select([sys.stdin], [], []) 
    return sys.stdin.readline() 

def main(): 
    """ Run the server, listen for commands """ 

    server = StreamServer(("0.0.0.0", 6000), handle) 
    print "Starting server" 
    gevent.signal(signal.SIGTERM, server.close) 
    gevent.signal(signal.SIGQUIT, server.close) 
    gevent.signal(signal.SIGINT, server.close) 

    server.start() 
    while True: 
     try: 
      a = raw_input("") 
      if a: 
       print "Received %s" % a 
      gevent.sleep(0) 
     except KeyboardInterrupt: 
      print "Received a shutdown signal, going down ..." 
      server.stop() 
      sys.exit(0) 

if __name__ == "__main__": 
    main() 

EDIT: Я переписать части кода, и теперь я понимаю глупость основной() - функция. Я опубликую его как отредактировать, если кто-то споткнется на этот вопрос и лучше поймет, как это сделать.

from gevent.signal import signal 

def get_console_input(): 
    """ Non-blocking console input to the server """ 

    select.select([sys.stdin], [], []) 
    # There's quite a bit of code here but it is input handling so 
    # for shortness's sake I've snipped everything and return the line read. 
    return sys.stdin.readline() 

def exit(server): 
    """ Quit the server gracefully """ 

    print "Received shutdown signal, going down. """ 
    server.close() 
    sys.exit(0) 

def main(): 
    """ The main function. Create and run the server, listen for commands and 
    append any command to the server so it can send them on to the clients """ 

    # Myserver is a class which inherits from gevent.server.StreamServer. 
    # Myserver could just as well be replaced by gevent.server.StreamServer. 

    server = MyServer(("0.0.0.0", PORT)) 
    print "Starting server" 

    # Add some signal handlers to quit the server gracefully. 
    gevent.signal(signal.SIGTERM, exit, server) 
    gevent.signal(signal.SIGQUIT, exit, server) 
    gevent.signal(signal.SIGINT, exit, server) 

    # Server started in async mode 
    server.start() 

    while True: 
     get_console_input() 
     gevent.sleep(0) 

if __name__ == "__main__": 
    main() 

ответ

5

Самый простой способ я нашел, чтобы сделать это, чтобы использовать gevent.socket.wait_read ждать, пока sys.stdin не может быть прочитан:

wait_read(sys.stdin.fileno()) 
return sys.stdin.readline() 

Я также написал небольшую обертку вокруг дескрипторов файлов, чтобы дать им неблокирующие .read() и .write() методы: https://gist.github.com/2915875

+0

Спасибо, похоже, что я ищу! – msvalkon

+0

Хорошо работает в OSX, но, похоже, не работает должным образом в Windows. Ошибка wait_read "IOError: [Errno 0] Нет ошибки" –