简体   繁体   English

当线程完成时退出的多线程Python服务器

[英]Multi-threaded Python server that exits when threads finish

Let's say you had a fairly basic client/server code, where each client creates three threads and multiple clients can connect at once. 假设您有一个相当基本的客户端/服务器代码,其中每个客户端创建三个线程,多个客户端可以一次连接。 I want the server to wait for an incoming connection, and once it starts getting connections, to run until there are no more threads running, then exit. 我希望服务器等待传入的连接,并在它开始获得连接后运行,直到没有更多的线程在运行,然后退出。 Code is similar to below. 代码类似于下面。 (ie, rather than the server "serve forever," I want it to exit once all the threads finish). (即,我希望服务器在所有线程完成后退出,而不是服务器“永远服务”)。

edit: I want the server to wait for incoming connections. 编辑:我希望服务器等待传入的连接。 Once the connections begin, it should keep accepting connections until there are no threads left running, then exit. 一旦连接开始,它应该继续接受连接,直到没有线程在运行,然后退出。 These connections will be somewhat sporadic. 这些联系将是零星的。

import socket
import threading

# Our thread class:
class ClientThread ( threading.Thread ):

   # Override Thread's __init__ method to accept the parameters needed:
   def __init__ ( self, channel, details ):

      self.channel = channel
      self.details = details
      threading.Thread.__init__ ( self )

   def run ( self ):

      print 'Received connection:', self.details [ 0 ]
      self.channel.send ( 'hello from server' )
      for x in xrange ( 10 ):
         print self.channel.recv ( 1024 )
      self.channel.close()
      print 'Closed connection:', self.details [ 0 ]

# Set up the server:
server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 2727 ) )
server.listen ( 5 )

# Have the server serve "forever":
while True:
   channel, details = server.accept()
   ClientThread ( channel, details ).start()

As per your comments, what you are looking for is to starting counting connections after the first one is made to the server, and to kill the server once there are no more existing connections. 根据您的评论,您要寻找的是在对服务器进行第一个连接后开始计算连接数,并在不再存在现有连接时杀死服务器。

An immediate problem with your current infinite while loop is that is blocks on each accept() . 当前的无限while循环的直接问题是每个accept()上的块。 So no matter what, it will always be waiting for another connection. 因此,无论如何,它将始终在等待另一个连接。 You would have to interrupt it from some other thread to get it out of that loop. 您必须从其他线程中中断它才能使其退出该循环。 But another solution would be to make your event loop larger, and the act of accepting a new connection is only one part of it. 但是另一种解决方案是使事件循环更大,并且接受新连接的行为只是其中一部分。 The loop should also be checking for a condition to exit. 该循环还应检查是否存在退出条件。

This example is only one possible way. 此示例只是一种可能的方法。 It makes use of a Queue.Queue to coordinate the work counter. 它利用Queue.Queue来协调工作计数器。

import socket
import threading
import select
from Queue import Queue

class ClientThread ( threading.Thread ):

   def __init__ ( self, channel, details, queue=None ):
      self.channel = channel
      self.details = details
      self.queue = queue
      threading.Thread.__init__ ( self )

   def run ( self ):

      if self.queue:
         self.queue.put(1)

      print 'Received connection:', self.details [ 0 ]
      self.channel.send ( 'hello from server' )
      for x in xrange ( 10 ):
         print self.channel.recv ( 1024 )
      self.channel.close()
      print 'Closed connection:', self.details [ 0 ]

      if self.queue:
         self.queue.get_nowait()

# Set up the server:
server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 2727 ) )
server.listen ( 5 )

rlist = [server]
work_queue = Queue()

def accept_client():
   channel, details = server.accept()
   ClientThread ( channel, details, work_queue ).start() 

accept_client()

while not work_queue.empty():
   server_ready, _, _ = select.select(rlist,[],[], .25)
   if server in server_ready:
      accept_client()

print "Shutting down"
server.close()
print "Exiting"

We use select.select as a simple way to detect activity on your server socket, but also with a timeout. 我们使用select.select作为检测服务器套接字上活动的简单方法,但是也会超时。 If the server is ready, then we accept the new connection. 如果服务器已准备就绪,则我们接受新连接。 If it reaches the .25 second timeout, we just loop again and wait. 如果达到.25秒超时,我们将再次循环并等待。

You will see that we create a queue and constantly check if its empty. 您将看到我们创建了一个队列并不断检查它是否为空。 The queue is passed into each thread. 队列被传递到每个线程。 When a thread is started, it logs some work into the queue. 启动线程时,它将一些工作记录到队列中。 The data is arbitrary. 数据是任意的。 Just a flag. 只是一个标志。 When the thread has completed, it will clear that item from the queue. 线程完成后,它将从队列中清除该项目。 The result is that after the first connection is received, the queue is no longer empty, and the loop will keep running. 结果是,在收到第一个连接后,队列不再为空,并且循环将继续运行。 If at any point the queue becomes empty (because all current threads have finished), the loop will break and the server will shut down. 如果队列在任何时候变空(因为所有当前线程均已完成),则循环将中断并且服务器将关闭。

If you break from the while loop, the process will wait until all the ClientThreads exit, and will then terminate. 如果您从while循环break ,则该过程将等待,直到所有ClientThreads退出,然后终止。

This will work because the client threads are non-daemon . 这将起作用,因为客户端线程是非守护程序 See threading.Thread.daemon for further details on this. 有关更多详细信息,请参见threading.Thread.daemon

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM