python - 在单线程 Python 应用程序中关闭 socketserver serve_forever()

标签 python sockets socketserver

我知道socketserver有一个方法shutdown()这会导致服务器关闭,但这仅适用于多线程应用程序,因为关闭需要从与 serve_forever() 所在的线程不同的线程调用正在运行。

我的应用程序一次只处理一个请求,所以我不使用单独的线程来处理请求,而且我无法调用 shutdown()因为它会导致死锁(它不在文档中,但在 socketserver 的源代码中直接说明)。

为了更好地理解,我将在此处粘贴我的代码的简化版本:

import socketserver

class TCPServerV4(socketserver.TCPServer):
  address_family = socket.AF_INET
  allow_reuse_address = True

class TCPHandler(socketserver.BaseRequestHandler):
  def handle(self):
    try:
       data = self.request.recv(4096)
    except KeyboardInterrupt:
       server.shutdown()

server = TCPServerV4((host, port), TCPHandler)
server.server_forever()

我知道此代码无效。我只是想向您展示我想完成的事情 - 在用户按下 CtrlC 时关闭服务器并退出应用程序,同时等待传入数据。

最佳答案

您可以在处理程序中本地启动另一个线程,然后从那里调用 shutdown

工作演示:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import SimpleHTTPServer
import SocketServer
import time
import thread

class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_POST(self):
        if self.path.startswith('/kill_server'):
            print "Server is going down, run it again manually!"
            def kill_me_please(server):
                server.shutdown()
            thread.start_new_thread(kill_me_please, (httpd,))
            self.send_error(500)

class MyTCPServer(SocketServer.TCPServer):
    def server_bind(self):
        import socket
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)

server_address = ('', 8000)
httpd = MyTCPServer(server_address, MyHandler)
try:
    httpd.serve_forever()
except KeyboardInterrupt:
    pass
httpd.server_close()

一些注意事项:

  1. 要终止服务器,请向 http://localhost:8000/kill_server 发送POST 请求。
  2. 我创建调用 server.shutdown() 的函数并从另一个线程运行它以解决我们讨论的问题。
  3. 我使用来自 Binding Socket: “Address already in use” 的建议使套接字立即可供重用(您可以再次运行服务器而不会出现[Errno 98] Address already in use 错误)。使用标准的 TCPServer,您将不得不等待连接超时才能再次运行您的服务器。

关于python - 在单线程 Python 应用程序中关闭 socketserver serve_forever(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10085996/

相关文章:

PHP 套接字 - 接受多个连接

python - python 中的 TimedRotatingFileHandler 的翻转没有发生

python - couchdb-python 更改通知

python - 属性错误 : 'WriteConcern' object has no attribute 'acknowledged'

Java套接字文件上传到服务器,服务器不获取字节数组的第一个字节

java - 从字符数组中删除所有空元素

java - 使用 3 个不同线程中的套接字监听 3 个不同的端口

python - 如何在 python tkinter 中绑定(bind) Ctrl+/?

PHP to Go 使用 Unix 域套接字

Python socket.send() 只能发送一次,然后socket.error : [Errno 32] Broken pipe occurred