python 中具有活动 TCP 连接的 HTTP 服务器
HTTP Server with active TCP connections in python
我正在 python 中编写一个伪 http 应用程序,其要求是:
- 它应该处理 HTTP 请求。
- 客户端和服务器之间的连接比请求-响应还长,即在向客户端发送响应后,底层 TCP 连接仍然有效。
- 服务器需要能够将数据发送到它已经打开连接的特定客户端。
我看过 twisted 和 python 的 TCPServer/BaseHTTPServer,但它们不太符合要求。在我看来,我有两个选择:
- 从 HTTP 服务器实现开始,覆盖我的连接管理方式。
- 有一个简单的套接字服务器,它将管理连接并在 "http" 服务器和客户端之间传递数据。
有没有人解决过类似的问题?关于其他方法的任何想法或哪一个是更好的选择?
谢谢!
编辑 1
我不能使用 HTTP 2 或网络套接字; HTTP <2 over TCP 是硬性要求。
由于您不能使用 websockets 或 http/2,并且您需要能够将数据从服务器推送到客户端,那么长轮询可能是剩下的最佳选择。
参见 https://github.com/twisted/nevow 上的 Nevow,了解通过 athena 模块实现长轮询的一种可能方式。
我最终覆盖了 http.server.HTTPServer 中的方法,它比预期的要少,而且全部来自标准包。
根据您的情况,以下内容最终可能会涉及更多,例如使用更结构化的 session 表示等。在这种情况下,您可能应该再次考虑更发达的框架,例如 twisted。
要点是:
- 使用 ThreadingMixIn - 因为连接是 long-lived,所以需要一个单独的处理程序线程以便一次处理多个连接。
- 请注意,如果您使用 BaseHTTPRequestHandler,则每次响应后连接都会关闭,除非有
Connection: keep-alive
header 或您在 EVERY 上设置了 self.close_connection = False
请求。
无论如何,让您入门的片段:
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
class MyHandler(BaseHTTPRequestHandler):
# Implement do_GET, do_POST, etc.
def handle_one_request(self):
super(MyHandler, self).handle_one_request()
self.close_connection = some_condition()
if self.close_connection:
# Remove the session from the server as it will be closed after this
# method returns
self.server.sessions.pop(self.client_address)
class MyServer(ThreadingMixIn, HTTPServer):
def __init__(self, addr_port, handler_class):
super(MyServer, self).__init__(addr_port, handler_class)
self.sessions = {} # e.g. (addr, port) -> client socket
def get_request(self):
"""Just call the super's method and cache the client socket"""
client_socket, client_addr = super(MyServer, self).get_request()
self.sessions[client_addr] = client_socket
return (client_socket, client_addr)
# You may also want to add the following
def server_close(self):
"""Close any leftover connections."""
super(MyServer, self).server_close()
for _, sock in self.sessions.items():
try:
sock.shutdown(socket.SHUT_WR)
except socket.error:
pass
sock.close()
我正在 python 中编写一个伪 http 应用程序,其要求是:
- 它应该处理 HTTP 请求。
- 客户端和服务器之间的连接比请求-响应还长,即在向客户端发送响应后,底层 TCP 连接仍然有效。
- 服务器需要能够将数据发送到它已经打开连接的特定客户端。
我看过 twisted 和 python 的 TCPServer/BaseHTTPServer,但它们不太符合要求。在我看来,我有两个选择:
- 从 HTTP 服务器实现开始,覆盖我的连接管理方式。
- 有一个简单的套接字服务器,它将管理连接并在 "http" 服务器和客户端之间传递数据。
有没有人解决过类似的问题?关于其他方法的任何想法或哪一个是更好的选择?
谢谢!
编辑 1 我不能使用 HTTP 2 或网络套接字; HTTP <2 over TCP 是硬性要求。
由于您不能使用 websockets 或 http/2,并且您需要能够将数据从服务器推送到客户端,那么长轮询可能是剩下的最佳选择。
参见 https://github.com/twisted/nevow 上的 Nevow,了解通过 athena 模块实现长轮询的一种可能方式。
我最终覆盖了 http.server.HTTPServer 中的方法,它比预期的要少,而且全部来自标准包。
根据您的情况,以下内容最终可能会涉及更多,例如使用更结构化的 session 表示等。在这种情况下,您可能应该再次考虑更发达的框架,例如 twisted。
要点是:
- 使用 ThreadingMixIn - 因为连接是 long-lived,所以需要一个单独的处理程序线程以便一次处理多个连接。
- 请注意,如果您使用 BaseHTTPRequestHandler,则每次响应后连接都会关闭,除非有
Connection: keep-alive
header 或您在 EVERY 上设置了self.close_connection = False
请求。
无论如何,让您入门的片段:
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
class MyHandler(BaseHTTPRequestHandler):
# Implement do_GET, do_POST, etc.
def handle_one_request(self):
super(MyHandler, self).handle_one_request()
self.close_connection = some_condition()
if self.close_connection:
# Remove the session from the server as it will be closed after this
# method returns
self.server.sessions.pop(self.client_address)
class MyServer(ThreadingMixIn, HTTPServer):
def __init__(self, addr_port, handler_class):
super(MyServer, self).__init__(addr_port, handler_class)
self.sessions = {} # e.g. (addr, port) -> client socket
def get_request(self):
"""Just call the super's method and cache the client socket"""
client_socket, client_addr = super(MyServer, self).get_request()
self.sessions[client_addr] = client_socket
return (client_socket, client_addr)
# You may also want to add the following
def server_close(self):
"""Close any leftover connections."""
super(MyServer, self).server_close()
for _, sock in self.sessions.items():
try:
sock.shutdown(socket.SHUT_WR)
except socket.error:
pass
sock.close()