Python套接字接受块 - 防止应用程序退出

时间:2009-07-18 17:23:40

标签: python sockets

我编写了一个非常简单的python类,它等待套接字上的连接。目的是将此类添加到现有应用程序中,并将数据异步发送到连接客户端。

问题是当等待socket.accept()时,我无法通过按ctrl-c来结束我的应用程序。我也无法检测到我的课程何时超出范围并通知它结束。

理想情况下,以下应用程序应在time.sleep(4)到期后退出。正如您在下面看到的,我尝试使用select,但这也会阻止应用程序响应ctrl-c。如果我能在主方法中检测到变量'a'超出范围,我可以设置退出标志(并减少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 个答案:

答案 0 :(得分:9)

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

(在Python 2.6及更高版本中,首选self.daemon = True。)

关键思想解释为here

  

整个Python程序何时退出   没有活着的非守护进程线程。

所以,你需要制作那些不应该只是通过自己活着来保持整个过程活着的线程的“守护进程”。顺便说一下,主线程始终是非守护进程。

答案 1 :(得分: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()后延迟一秒钟,这是不良行为。这通常很容易修复:创建一个可以写入的唤醒管道(),并将其包含在选择中;虽然这是非常基本的,但我找不到任何方法在Python中做到这一点。 (os.pipe()返回文件描述符,而不是我们可以写入的文件对象。)我没有深入挖掘,因为它与问题相关。