我编写了一个非常简单的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()
答案 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()返回文件描述符,而不是我们可以写入的文件对象。)我没有深入挖掘,因为它与问题相关。