Python socket принимает блоки - предотвращает выход из приложения - PullRequest
8 голосов
/ 18 июля 2009

Я написал очень простой класс Python, который ожидает соединения в сокете. Намерение состоит в том, чтобы вставить этот класс в существующее приложение и асинхронно отправлять данные подключающимся клиентам.

Проблема в том, что при ожидании в socket.accept () я не могу завершить свое приложение нажатием ctrl-c. Также я не могу определить, когда мой класс выходит из области видимости, и уведомить его об окончании.

В идеале приложение, указанное ниже, должно завершиться по истечении time.sleep (4). Как вы можете видеть ниже, я попытался использовать select, но это также не позволяет приложению реагировать на ctrl-c. Если бы я мог обнаружить, что переменная 'a' вышла из области видимости в методе main, я мог бы установить флаг выхода (и сократить время ожидания для select, чтобы сделать его отзывчивым).

Есть идеи?

спасибо


import sys
import socket
import threading
import time
import select

class Server( threading.Thread ):
    def __init__( self, i_port ):
        threading.Thread.__init__( self )
        self.quitting = False
        self.serversocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
        self.serversocket.bind( (socket.gethostname(), i_port ) )
        self.serversocket.listen(5)
        self.start()

    def run( self ):
        # Wait for connection
        while not self.quitting:
            rr,rw,err = select.select( [self.serversocket],[],[], 20 )
            if rr:
                (clientsocket, address) = self.serversocket.accept()
                clientsocket.close()

def main():
    a = Server( 6543 )
    time.sleep(4)

if __name__=='__main__':
  main()

Ответы [ 2 ]

9 голосов
/ 18 июля 2009

Добавьте self.setDaemon(True) к __init__ до self.start().

(в Python 2.6 и более поздних версиях self.daemon = True является предпочтительным).

Ключевая идея объясняется здесь :

Вся программа Python завершается, когда не осталось живых потоков, не являющихся демонами.

Итак, вам нужно создать «демонов» из тех потоков, которые не должны поддерживать весь процесс живым, просто живя сами. Кстати, основной поток всегда не является демоном.

4 голосов
/ 18 июля 2009

Я не рекомендую функцию setDaemon для нормального выключения. Это небрежно; вместо того, чтобы иметь чистый путь отключения для потоков, он просто убивает поток без возможности очистки. Хорошо установить его, чтобы ваша программа не застревала, если основной поток неожиданно завершил работу, но это не хороший нормальный путь завершения работы, за исключением быстрых хаков.

import sys, os, socket, threading, time, select

class Server(threading.Thread):
    def __init__(self, i_port):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.quitting = False
        self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.serversocket.bind((socket.gethostname(), i_port))
        self.serversocket.listen(5)
        self.start()

    def shutdown(self):
        if self.quitting:
            return

        self.quitting = True
        self.join()

    def run(self):
        # Wait for connection
        while not self.quitting:
            rr,rw,err = select.select([self.serversocket],[],[], 1)
            print rr
            if rr:
                (clientsocket, address) = self.serversocket.accept()
                clientsocket.close()

        print "shutting down"
        self.serversocket.close()

def main():
    a = Server(6543)
    try:
        time.sleep(4)
    finally:
        a.shutdown()

if __name__=='__main__':
  main()

Обратите внимание, что это приведет к задержке на одну секунду после вызова shutdown (), что является плохим поведением. Обычно это легко исправить: создайте канал пробуждения (), в который вы можете писать, и включите его в select; но хотя это очень просто, я не смог найти никакого способа сделать это в Python. (os.pipe () возвращает файловые дескрипторы, а не файловые объекты, в которые мы можем записать.) Я не стал копать глубже, поскольку это касается вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...