2014-01-14 2 views
0

У меня есть этот проект сервера, который развивает новые дети после нового клиентского соединения. Тогда в зависимости от клиентской команды дочерний сервер выполняет некоторую работу внутри обработчика функции (соединения).Родительский серверный вилок должен своевременно покидать

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

Вопрос в том, где я должен поместить эту сигнальную функцию для опции прерывания клавиатуры Ctrl + C. signal.signal (signal.SIGINT, signal_handler)

Спасибо ребята за помощь симпатичную и почти смарт-самку. :)

children_list = [] 
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
conn.bind((HOST, PORT)) 
conn.listen(5) 
print("Listening on TCP port %s" % PORT) 

def reaper(pids): 

     while children_list:       
     pid,stat = os.waitpid(0, os.WNOHANG) 

     if not pid: 

      break 

     pids.remove(pid) 


def handler(connection):      

    cmd = connection.recv(socksize) 

def signal_handler(signal, frame): 
    print 'You pressed Ctrl+C!' 
    sys.exit(0) 

def accept():         

while 1: 
     global connection         
      connection, address = conn.accept() 
      print "welcome new client!" 
     reaper(children_list) 
      pid = os.fork()      
      if pid:#parent 
       children_list.append(pid) 
       connection.close() 

     else:#child  
       handler(connection) 


accept() 
+0

Это действительно поможет исправить отступы, чтобы это было доступно для чтения и запуска. Как бы то ни было, я могу _guess_, что он делает, но было бы лучше, если бы мне не пришлось. – abarnert

+0

И как примечание, какая-то конкретная причина, по которой вы используете 'fork' вместо' threading'? Есть много веских причин (например, если дети не похожи на типичных обработчиков серверов, которые в основном ждут ввода-вывода, но им нужно много работы с ЦП ... или если вы хотите отделить их, чтобы вы могли отключить акцептор, но оставить существующих клиентов, работающих ... и т. д.), но мне любопытно, в чем причина. – abarnert

+0

И последнее примечание: сервер TCP обычно хочет вызвать 'conn.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)' перед вызовом 'bind'. (См. [Здесь] (http://www.unixguide.net/network/socketfaq/4.5.shtml) для древних часто задаваемых вопросов и [здесь] (http://hea-www.harvard.edu/~fine/Tech /addrinuse.html) для получения более подробной информации.) – abarnert

ответ

0

Вопрос, где я должен поместить эту функцию сигнала для Ctrl + C вариант прерывания клавиатуры. signal.signal (signal.SIGINT, signal_handler)

Везде вы хотите, до тех пор, пока это после того, как вы определяете signal_handler и перед вызовом accept.

Я не уверен, что обработчик сигналов на самом деле то, что вы хотите. То, что вы на самом деле делаете, на большинстве платформ выйдет сразу же, как вы просите об этом, заставив ребят вернуться к init или launchd или тому подобное. Но вы действительно хотите дождаться всех детей. Таким образом, вы не можете позвонить exit.

В POSIX вы не можете позвонить waitpid внутри передатчика сигнала. Обработчики сигналов Python не являются реальными обработчиками сигналов, поэтому этот может не иметь отношения к делу, но я не думаю, что этот факт гарантирован в любом месте. Если вы хотите взять на себя риск, вы можете попробовать дождаться всех детей прямо в signal_handler перед вызовом exit и посмотреть, работает ли он на вашей платформе.

Однако стандартный способ POSIX для этого состоит в том, чтобы обработчик сигнала устанавливал некоторый глобальный флаг и возвращался. Затем основная программа проснется от accept или любого другого блокирующего вызова, ожидающего его с ошибкой EINTR, после чего она может проверить флаг - если это правда, время ожидания на дочерних элементах и ​​выйти; в противном случае снова вернитесь в цикл и accept.

Но все это не обязательно необходимо. Обработчик SIGINT по умолчанию должен просто поднять KeyboardInterrupt, а это значит, что если вы не устанавливаете пользовательский обработчик сигнала, все, что вам действительно нужно сделать, это поймать это исключение. Другими словами, просто замените последнюю строку следующим образом:

try: 
    accept() 
except KeyboardInterrupt: # or maybe BaseException 
    # wait for children, blocking instead of WNOHANG of course 
    sys.exit(0) 
+0

Я хочу дождаться всех работающих детей ... как я сказал выше «Я хочу остановить родительский сервер, и до этого пусть родитель ждет всех работающих детей». –

+0

Я попытался поставить signal.signal (signal.SIGINT, signal_handler) «в любом месте» ... он просто выходит правильно, и родитель не ждет детей ... поэтому получаю ошибки. –

+0

@NatashaAlmazova: Да, но это не из-за того, где вы помещаете код, потому что ваш обработчик сигнала сразу же выходит, вызывая 'sys.exit'. На большинстве платформ * nix это делает именно то, о чем вы просили, заставляя ребят переписываться на 'init' или' launchd' или аналогичные. Вот почему я сказал: «Я не уверен, что обработчик сигналов - это то, что вы хотите». – abarnert

Смежные вопросы