2009-07-18 81 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