webプロキシ HTTP1.0 ヒント CS-B3 ネットワークプログラミング &情報科学科実験I
このスライドについて このスライドでは皆さんがプログラムを書いたり,関数を調べたりする過程で行き詰ると予想される部分について簡単に解説します. このスライドの目的は自主学習のサポートであり,説明が簡略化されています.完全な理解には自主学習が必要なので注意してください.
目次 webプロキシとは 何を実装すればよいのか 実装方法の例 webサーバの特定方法 実装をする上での注意
webプロキシとは 一般的な通信は直接通信 webサーバ ブラウザ
webプロキシとは proxy = 「代理」 webサーバとのデータのやりとりを中継する webサーバ ブラウザ $./proxy プロキシ
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ プロキシ $./proxy proxy側 listen() webサーバ
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ プロキシ $./proxy proxy側 listen() webサーバ ブラウザ側の connect()
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ プロキシ $./proxy webサーバ listen() プロキシ側で accept()
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ プロキシ $./proxy ブラウザからの リクエスト webサーバ listen()
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ プロキシ $./proxy リクエストから webサーバを特定 listen() リクエストから webサーバを特定
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ プロキシ $./proxy webサーバ listen() connect()
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ $./proxy プロキシ webサーバが accept()
何を実装すればよいのか プログラムの流れ webサーバ ブラウザからの リクエストを 転送 ブラウザ $./proxy プロキシ
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ $./proxy プロキシ webサーバからの レスポンス
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ $./proxy プロキシ webサーバからの レスポンスを 転送
何を実装すればよいのか プログラムの流れ webサーバ ブラウザ $./proxy プロキシ ソケットクローズ
何を実装すればよいのか HTTP1.0では 1リクエスト + 1レスポンス = 1コネクション 各リクエストごとに接続を確立します.
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ $./proxy プロキシ
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ プロキシ $./proxy listen() webサーバ listen() ブラウザ側の connect()
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ プロキシ $./proxy listen() プロキシ側で accept()
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ プロキシ $./proxy listen用ソケットは残しておく webサーバ listen() 別スレッド,または別プロセス proxy accept()したら 後は並列処理に任せる
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ プロキシ $./proxy listen用ソケットは残しておく webサーバ listen() 別スレッド,または別プロセス proxy
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ プロキシ $./proxy listen() ブラウザ側の connect() 別スレッド,または別プロセス proxy
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ プロキシ $./proxy listen() プロキシ側で accept() 別スレッド,または別プロセス proxy
何を実装すればよいのか さらに,ブラウザからのconnectを複数受け付けるには webサーバ ブラウザ プロキシ $./proxy listen用ソケットは残しておく webサーバ listen() 別スレッド,または別プロセス proxy proxy
実装方法の例 main { listenSocket = listen中のソケットを作成; sockaddr_in変数の各種メンバの設定; bind(); listen(); while (1) { browserSocket = accept(listenSocket, …); /* ブラウザからlistenSocketへの接続要求をaccept(); */ スレッド(またはプロセス)の作成; /*子スレッドor子プロセスに送受信処理を実行させる*/ /*browserSocketをスレッド(またはプロセス)に渡す*/ }/*main関数はaccept→子スレッドorプロセスの作成を繰り返す*/ } ※あくまでも一例です.また,引数や実装方法が簡略化されています.
スレッドorプロセス によって作成した子の中で 実装方法の例 スレッド(またはプロセス) { recv(browserSocketからの文字列 → buffer); webserverSocket = socket(); hostName = bufferからwebサーバのホスト名を抜き出す; hostAddress = hostNameからwebサーバのIPアドレスを求める; hostPort = webサーバならば通常は80を代入;(well-known port) sockaddr_in型変数のメンバへの設定; connect(); send(bufferの文字列 → webserverSocket) while(1) { browserSocketまたはwebserverSocketが読み取り可能になるまで待機; if (browserSocketからrecv()できるなら) { recv(browserSocketからの文字列 → buffer); /* ① */ if (recv()が失敗したら) break; send(bufferの文字列 → webserverSocket) /* リクエストの転送 */ if (①のrecv()の結果,browserSocketがクーロズされていたとわかった(つまり0バイト受信)) { break; } if (webserverSocketからrecv()できるなら) { recv(webserverSocketからの文字列 → buffer); /* ② */ send(bufferの文字列 → browserSocket) /* レスポンスの転送 */ if (②のrecv()の結果,webserverSocketがクーロズされていたとわかった(つまり0バイト受信)) { close(browserSocket); close(webserverSocket); return 0; スレッドorプロセス によって作成した子の中で Selectを用いればよい ※あくまでも一例です.また,引数や実装方法が簡略化されています.
HTTPのリクエスト,レスポンスはテキストデータである. webサーバの特定方法 HTTPのリクエスト,レスポンスはテキストデータである. HTTP1.0 プロキシを用いたリクエスト GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n Host: www.inf.shizuoka.ac.jp\r\n (以下省略)
※接続先ポート番号は今回は80番で固定でOK webサーバの特定方法 HTTP1.0 プロキシを用いたリクエスト GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n Host: www.inf.shizuoka.ac.jp\r\n (以下省略) ホスト名が特定できた =名前解決でIPアドレスが分かる ※接続先ポート番号は今回は80番で固定でOK
※接続先ポート番号は今回は80番で固定でOK webサーバの特定方法 HTTP1.0 プロキシを用いたリクエスト GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n Host: www.inf.shizuoka.ac.jp\r\n (以下省略) “Host: ”がないならば “GET”からホスト名を特定 ※接続先ポート番号は今回は80番で固定でOK
実装上の注意 プロキシを使う場合と使わない場合ではリクエストが異なる! webブラウザによっては… プロキシ使用 プロキシ未使用 GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n Host: www.inf.shizuoka.ac.jp\r\n (以下省略) プロキシ未使用 GET / HTTP/1.0\r\n Host: www.inf.shizuoka.ac.jp\r\n (以下省略)
実装上の注意 プロキシを使う場合と使わない場合ではリクエストが異なる! webブラウザによっては… プロキシ使用 プロキシ未使用 GET http://www.inf.shizuoka.ac.jp/ HTTP/1.0\r\n Host: www.inf.shizuoka.ac.jp\r\n (以下省略) プロキシ未使用 GET / HTTP/1.0\r\n Host: www.inf.shizuoka.ac.jp\r\n (以下省略) リクエストをwebサーバに転送するときは“GET”メソッドから “http://ホスト名”を削除しておこう!! ※メソッドは”GET”だけとは限りません あくまでも“http://ホスト名”を削除するだけで それ以外の部分をプロキシ側で書き換えてはいけません
まとめ webプロキシプログラムは ブラウザからのconnect()をaccept()する ブラウザとの通信用のソケットを並列処理に持っていく 以下,並列処理 ブラウザからリクエストを受け取る ブラウザのリクエストからwebサーバを特定する webサーバとの通信用ソケットを作成し,connect()する ブラウザのリクエスト,webサーバからのレスポンスを転送する(このとき,リクエストはあらかじめ適切に変換しておく) ソケットを閉じる