在python中具有活动TCP连接的HTTP Server

时间:2016-10-13 11:12:33

标签: python tcp twisted httpserver

我在python中编写一个伪http应用程序,其要求是:

  1. 它应该处理HTTP请求。
  2. 客户端和服务器之间的连接比请求响应更长,即在将响应发送到客户端后,底层TCP连接仍然存在。
  3. 服务器需要能够将数据发送到已经打开连接的特定客户端。
  4. 我查看了twisted和python的TCPServer / BaseHTTPServer,但它们并不适合这个账单。我看到它的方式,我有两个选择:

    1. 从HTTP服务器实施开始,然后覆盖我的方式进行连接管理。
    2. 有一个简单的套接字服务器,用于管理连接并在“http”服务器和客户端之间传递数据。
    3. 是否有人处理类似问题?关于其他方法的任何想法或哪个更好的选择?

      谢谢!

      编辑1 我不能使用HTTP 2或Web套接字; HTTP< 2 over TCP是一项艰难的要求。

2 个答案:

答案 0 :(得分:1)

由于您无法使用websockets或http / 2,并且您需要能够将数据从服务器推送到客户端,因此长轮询可能是剩余的最佳选择。

https://github.com/twisted/nevow的Nevow,通过athena模块实现长轮询的一种可能方式。

答案 1 :(得分:0)

我最终覆盖了http.server.HTTPServer中的方法,它的工作量少于预期,而且全部来自标准软件包。

根据您的情况,以下内容可能会更多地涉及到,例如:使用更结构化的会话表示等。在这种情况下,你应该再考虑更像twisted这样的框架。

要点是:

  • 使用ThreadingMixIn - 由于连接是长期存在的,因此需要一个单独的处理程序线程,以便一次连接多个连接。
  • 请注意,如果您使用的是BaseHTTPRequestHandler,则会在每次回复后关闭连接,除非有Connection: keep-alive标头或您在每个请求上设置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()