首页 文章

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

提问于
浏览
1

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

  • 它应该处理HTTP请求 .

  • 客户端和服务器之间的连接比请求响应更长,即在将响应发送到客户端后,底层TCP连接仍然存在 .

  • 服务器需要能够将数据发送到已经打开连接的特定客户端 .

我查看了twisted和python的TCPServer / BaseHTTPServer,但它们并不适合这个账单 . 我看到它的方式,我有两个选择:

  • 从HTTP服务器实现开始,并覆盖我的方式到连接管理 .

  • 有一个简单的套接字服务器,它将管理连接并在"http"服务器和客户端之间传递数据 .

有人解决了类似的问题吗?关于其他方法的任何想法或哪一个将是更好的选择?

谢谢!

EDIT 1 我无法使用HTTP 2或网络套接字; HTTP <2 over TCP是一项艰难的要求 .

2 回答

  • 0

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

    有关可能通过athena模块执行长轮询的信息,请参阅位于https://github.com/twisted/nevow的Nevow .

  • 1

    我最终覆盖了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()
    

相关问题