我正在尝试用python构建一个真正的非阻塞https服务器。如果每个人都玩得很好,下面的最小代码就可以正常工作:

import BaseHTTPServer
import SimpleHTTPServer
import SocketServer
import ssl

class ThreadedHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
    pass

httpd = ThreadedHTTPServer(('localhost', 4443), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile="localhost.key", certfile="localhost.pem", server_side=True)
httpd.serve_forever()

但是,问题是,该服务器至少在tls握手期间阻塞。
测试条件:
$ nc localhost 4443  # leave this open

然后(在另一个终端中):
$ wget --no-check-certificate https://localhost:4443/
--2014-10-23 16:55:54--  https://localhost:4443/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:4443... connected.

wget进程阻塞,表示服务器中的某些内容被阻塞。一旦我关闭NC进程,wget将继续。这显然根本不实际。
如何在python中获得真正的非阻塞https服务器,最好不要附加第三方软件?
我应该提到,在没有tls(即,没有wrap_套接字行)的情况下,同样的代码可以正常工作。
Steffen Ullrich指出了如何做到这一点:将do_handshake_on_connect=False传递到wrap_socket,然后自己握手。在这种情况下,子类BaseHTTPServer.HTTPServer,重写handle,然后按照python文档中所示进行握手(套接字被称为self.request),然后调用super方法。

最佳答案

您必须通过用ssl.wrap_socket调用do_handshake_on_connect=False来进行非阻塞ssl接受,然后自己调用do_handshake直到成功。见https://docs.python.org/3/library/ssl.html#notes-on-non-blocking-sockets
您还可以简单地使用Tornado这是一个用python编写的web服务器,它还执行完全无阻塞的ssl处理。即使您不想自己使用它,您也可以查看源代码来了解这是如何完成的(搜索do_handshake)。

10-08 07:10
查看更多