は、残念ながら、私は本当にしないでください:-)私は14だと学ぶために多く持っているように、これは単に試用版とヘルプははるかに高く評価されているコードについては申し訳ありませんあなたのコードがどのように機能すべきかを見てください。ここでは、単純なHTTPプロキシのように見えますか? 基本的なプロキシサーバーではどうすればよいですか:
- クライアントからの接続を受け入れ、HTTP要求を受け取ります。
- リクエストを解析し、その宛先を抽出します。
- フォワード要求と応答。
- (オプション)サポート
Connection: keep-alive
。
非常に単純化されたコードをステップバイステップで作成してみましょう。
プロキシはどのようにクライアントを受け入れますか。ソケットが作成され、パッシブモードに移動する必要があります。
import socket, select
sock = socket.socket()
sock.bind((your_ip, port))
sock.listen()
while True:
client_sock = sock.accept()
do_stuff(client_sock)
TCPコネクションが確立されると、それは要求を受ける時間です。我々はこのような何かを取得しようとしていると仮定しましょう:TCPでは
GET /?a=1&b=2 HTTP/1.1
Host: localhost
User-Agent: my browser details
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
を、メッセージの境界は保持されませんので、我々は(GETリクエスト用)は、少なくとも最初の2行を取得するまで、我々は知っているために待たなければなりません何後で行うには:我々は、リモートホスト名を持ってたら、それは要求と応答を転送するための時間
def do_stuff(sock):
data = receive_two_lines(sock)
remote_host = parse_request(data)
です:
def do_stuff(client_sock):
data = receive_two_lines(client_sock)
remote_host = parse_request(data)
remote_ip = socket.getaddrinfo(remote_host) # see the docs for exact use
webserver = socket.socket()
webserver.connect((remote_ip, 80))
webserver.sendall(data)
while it_makes_sense():
client_ready = select.select([client_sock], [], [])[0]
web_ready = select.select([webserver], [], [])[0]
if client_ready:
webserver.sendall(client_sock.recv(1024))
if web_ready:
client_sock.sendall(webserver.recv(1024))
select
に注意してください - これがあれば、我々が知っている方法ですリモートピアが私たちにデータを送ってきました。再び、メッセージの境界はTCPに保存されていないので、
- チャンスは、あなたが単一
client_sock.recv(1024)
呼び出しで、いくつかのGETリクエストを取得します:私は実行して、このコードをテストして行うには、左のものがありませんでした。おそらく、データを受け取るたびに追加のリクエストを調べるでしょう。
- リクエストは、POST、HEAD、PUT、DELETE、およびその他のタイプのリクエストで異なる場合があります。それに応じて解析します。
- ブラウザとサーバーは通常、ヘッダーに
Connection: keep-alive
オプションを設定することで1つのTCP接続を利用しますが、ドロップすることもできます。リモートピアによって閉じられた切断とソケットを検出する準備ができている(簡単に言うと、これはwhile it_makes_sense()
と呼ばれています)。
bind
、listen
、accept
、recv
、send
、sendall
、getaddrinfo
、select
- これらすべての機能が例外をスローすることができます。それを捕らえてそれに応じて行動するほうがよい。
- コードは現在、一度に1つのサーバーになります。
このフォーマットは、 'server()'の内部で受け入れている接続と 'server()'をもう一度呼び出すため、変です。それは意図的なのでしょうか? –