我已經調查了一下這個問題。 使插座表現得像兩臺不同的服務器一樣容易(取決於所接收數據的類型)。這裏最糟糕的是python的_ssl庫直接從socket._socket中讀取,它是一個本地python對象,因此無法正常掛接。
一種方法是編寫一個C模塊,它將鉤住原生Python套接字。 另一個解決方案是擁有1個前端和2個後端(https和http)。 Frontend監聽4443並決定是否應該使用https後端或http後端進行連接。您可以將相同的處理程序添加到兩臺服務器,並且它們的行爲方式相同。另一個問題是,在後端我們不知道客戶端的IP地址,但有一些解決方法(像前端將要保留的後端將要查看的dict {(前端到後端源端口號):客戶端IP} 。
與C解決方案相比,第二個看起來很骯髒,但在這裏。
import BaseHTTPServer, SimpleHTTPServer
import ssl
import socket
import select
import threading
FRONTEND_PORT = 4443
BACKEND_PORT_SSL = 44431
BACKEND_PORT_HTTP = 44432
HOST = 'localhost'
httpd_ssl = BaseHTTPServer.HTTPServer((HOST, BACKEND_PORT_SSL), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd_ssl.socket = ssl.wrap_socket (httpd_ssl.socket, certfile='key.pem', server_side=True)
httpd_direct = BaseHTTPServer.HTTPServer((HOST, BACKEND_PORT_HTTP), SimpleHTTPServer.SimpleHTTPRequestHandler)
def serve_forever(http_server):
http_server.serve_forever()
def categorize(sock, addr):
data = sock.recv(1)
if data == '\x16':
port = BACKEND_PORT_SSL
else:
port = BACKEND_PORT_HTTP
other_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
other_sock.connect((HOST, port))
other_sock.send(data)
inp = [sock, other_sock]
select_timeout = 1.0
try:
while 1:
r,w,x = select.select(inp,[],[],select_timeout)
if not r:
continue
for s in r:
o_s = inp[1] if inp[0]==s else inp[0]
buf = s.recv(4096)
if not buf:
raise socket.error
o_s.send(buf)
except socket.error:
pass
finally:
for s in inp:
s.close()
threading.Thread(target=serve_forever, args=(httpd_ssl,)).start()
threading.Thread(target=serve_forever, args=(httpd_direct,)).start()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, FRONTEND_PORT))
sock.listen(10)
while True:
conn, addr = sock.accept()
threading.Thread(target=categorize, args=(conn, addr)).start()
哈克!我喜歡它。 – d33tah
關於第一個想法。可以鉤住sock_recv(PySocketSockObject * s,PyObject * args)。但是這會影響所有套接字。所以我們必須找到區分鉤狀和非鉤狀插座的好方法。例如使用全局字典,但每個recv的字典查找將花費相當多,我不知道我們是否可以在PySocketSockObject結構中至少存儲一點。所以第一個解決方案更加骯髒。 –
嗯,爲什麼不可能創建一個包含_sock對象的類,該對象的行爲就像真正的_sock和被包裝的對象之間的代理一樣? – d33tah