想要向一个现有的基于 SocketServer.TCPServer 类的 TCP 服务器添加 SSL 支持。在该服务器的 TCPServer 类的默认构造函数中添加了 ssl.wrap_socket() 调用后,启动服务器时未出现错误。然而,修改了简单的测试客户端以支持 SSL 并连接到服务器后,connect 调用会阻塞。
2、解决方案
第一个答案中给出了两种解决方法:
-
在接受连接时对套接字进行封装,而不是在绑定之后。这可以通过在 MyTCPServer 类中重写 get_request() 方法来实现。
-
提前封装套接字,但推迟与客户端握手,直到接受连接。这可以通过在 MyTCPServer 类中重写 server_bind() 和 get_request() 方法来实现。
第二个答案中给出了另一种解决方案,其中使用了 OpenSSL 包来构建 SSL 上下文并使用 SSL.Connection 类封装套接字。
以下列出了上述提到的两个解决方案的代码示例:
解决方案 1:
class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
def get_request(self):
http://www.jshk.com.cn/mb/reg.asp?kefu=xiaoding;//爬虫IP免费获取;
(socket, addr) = SocketServer.TCPServer.get_request(self)
return (ssl.wrap_socket(socket, server_side=True, certfile="cert.pem"),
addr)
class MyStreamRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
# Handle the request using the encrypted socket
pass
class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
def server_bind(self):
SocketServer.TCPServer.server_bind(self)
self.socket = ssl.wrap_socket(
self.socket, server_side=True, certfile="cert.pem",
do_handshake_on_connect=False)
def get_request(self):
(socket, addr) = SocketServer.TCPServer.get_request(self)
socket.do_handshake()
return (socket, addr)
class MyStreamRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
# Handle the request using the encrypted socket
pass
解决方案 2:
import ssl
import socket
class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass)
ctx = ssl.SSLContext(ssl.SSLv23_METHOD)
cert = 'cert.pem'
ctx.use_privatekey_file(cert)
ctx.use_certificate_file(cert)
self.socket = ssl.SSLSocket(ctx, socket.socket(self.address_family,
self.socket_type))
if bind_and_activate:
self.server_bind()
self.server_activate()
class MyStreamRequestHandler(SocketServer.StreamRequestHandler):
def setup(self):
self.connection = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
def handle(self):
# Handle the request using the encrypted socket
pass
希望这些解决方案对您使用 SSL 支持的 TCP 服务器有所帮助。