2009-07-18 51 views
8

我寫了一個非常簡單的python類,它等待套接字上的連接。目的是將這個類粘貼到現有的應用程序中,並異步地將數據發送到連接客戶端。Python套接字接受塊 - 阻止應用程序退出

問題是,當在socket.accept()上等待時,我無法按ctrl-c來結束我的應用程序。當我的課程超出範圍並通知它結束時,我也無法檢測到。

理想情況下,下面的應用程序應該在time.sleep(4)過期後退出。正如你在下面看到的,我嘗試使用select,但是這也阻止了應用程序響應ctrl-c。如果我可以檢測到變量'a'已經超出了主方法的範圍,我可以設置退出標誌(並減少選擇的超時時間以使其響應)。

任何想法?

感謝


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() 

回答

9

self.start()之前添加self.setDaemon(True)__init__

(在Python 2.6和更高版本中,self.daemon = True是首選)。

的核心思想是解釋here

時 沒有活着​​的非守護線程留給整個Python程序退出。

因此,您需要爲那些不應該讓整個過程保持活力的線程「守護進程」,而只需要自己活着。順便提一下,主線程始終是非守護進程。

+0

謝謝你,它做到了。我試過 self.daemon = True 但這沒有做任何事情(我在Win32上運行python 2.5)。把它改成self.setDaemon(True)雖然做到了! 謝謝! – 2009-07-18 20:02:46

4

我不推薦正常關機的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()返回文件描述符,而不是我們可以寫入的文件對象。)我不深究,因爲它與問題相切。

+0

您可以使用os.fdopen將filedescriptor包裝到Python文件對象中。但是我不同意,除非setDaemon在線程中不需要特別的清理,否則只有小的但可有可無的複雜功能。 – 2009-07-18 18:54:25