教育サーバーのページ
オンラインテキスト目次
システムプログラミング演習
HTTPは、TCP/IPにおけるアプリケーション層に位置し、ブラウザからの一つの 要求に対して、Webサーバは一つの応答を返す。 HTTPは、以下のようなリクエストメッセージとレスポンスメッセージから構成 される。
リクエスト(要求)メッセージ
WebブラウザからWebサーバに対して、データを要求する時送るメッセージ である。リクエスト(要求)メッセージの形式は、以下のようになる。
リクエストメソッド一覧は、以下のようになる。
- リクエストライン
リクエストメソッド URI プロトコルバージョン
- ヘッダ(必要に応じてブラウザにより指定)
フィールド名: フィールド値 {[;パラメータ名=パラメータ値]}
- ボディ
(空行)
- GET
URIで指定される資源の内容を取得する
- HEAD
URIで指定される資源に関する情報だけを取得し、内容自体は取得しない
- POST
URIで指定される資源にデータを送り、またその資源の内容を取得する
リクエスト(要求)メッセージの例を以下に示す。 たとえば、http://www.hoge.ac.jp/index.htmlに対応するリクエスト(要求) メッセージは、
GET /index.html HTTP/1.1 HOST: www.hoge.ac.jp (空行)となる。
レスポンス(応答)メッセージ
リクエストメッセージに対するWebサーバの応答メッセージである。 メッセージの形式は以下のようになる。
- ステータスライン
HTTPバージョン ステータスコード 結果フレーズ
- ヘッダ(必要に応じてブラウザにより指定)
フィールド名: フィールド値 {[;パラメータ名=パラメータ値]}
- ボディ
HTML文本体ステータスコードの例を以下に示す。
- 1XX (カテゴリー)
インフォメーション (カテゴリ−の意味)
- 2XX
正常終了
- 3XX
リダイレクト(処理の変更通知)
- 4XX
クライアントエラー- 5XX
サーバエラーレスポンスメッセージの例を以下に示す。
HTTP/1.1 200 OK Data: Mon, 21 Apr 2003 09:15:00 GMT Server: Apache/1.3 26(Unix) PHP/4.22 Last-Modified: Fri, 04 Apr 2003 04:32:48 GMT Etag: “10028-7fbf-3e8d0af0” Content-Length: 32703 Content-Type: text/html <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”> <HTML> <HEAD> <TITLE> TUIS /Eeducation Domain</TITLE> </HEAD> ……… <BODY> ……… </BODY> </HTML>
HTTPを理解するために、他のコンピュータと通信をおこなうプロトコル であるtelnetを用いて、Webサーバにリクエストメッセージを送信し、 どのようなレスポンスメッセージが返送されるかを調べよう。
Windows NT/2000/XP/Vista/7では、telnetウィンドウは開けないので、 コマンドプロンプトを起動する。コマンドプロンプトにおいて、
C:\> telnet ↓(Enterを示す)
と打ち込み、telnetを起動する。
ただし、Windows 7では、telnetはデフォルトでは無効化設定されている。 そこで、コントロールパネルにある「プログラムと機能」を開き、左側の メニューに「Windowsの機能の有効化または無効化」という項目があるので、 これをクリックすると、Windowsの機能の画面が現れるので、「Telnetクライアント」 を有効にする。
Microsoft Telnet> set localecho ↓(Enterを示す)
Microsoft Telnet> set codeset Shift JIS ↓(Enterを示す)(日本語のページ)
Microsoft Telnet> open www.hoge.ac.jp 80 ↓(Enterを示す)
と打ち込み、ローカルエコーの設定、文字コードの設定、www.hoge.ac.jpへの 接続をそれぞれおこなう。英語のページの場合には、codesetの設定を以下の ようにおこなう。
Microsoft Telnet> set codeset JIS Kanji↓(Enterを示す)(自己紹介と英語のページ)
その後、telnetのウィンドウにおいて、次のリクエストを送信する。
GET /index.html HTTP/1.1 ↓(Enterを示す)
HOST: www.hoge.ac.jp 80 ↓(Enterを示す)
↓(Enterを示す)
すると、Webサーバから以下のようなレスポンスメッセージが送信される。
HTTP/1.1 200 OK Data: Mon, 21 Apr 2003 09:15:00 GMT Server: Apache/1.3 26(Unix) PHP/4.22 Last-Modified: Fri, 04 Apr 2003 04:32:48 GMT Etag: “10028-7fbf-3e8d0af0” Content-Length: 32703 Content-Type: text/html <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”> <HTML> <HEAD> <TITLE> TUIS /Eeducation Domain</TITLE> </HEAD> ……… <BODY> ……… </BODY> </HTML>
問題-1
ただし、報告ではヘッダ情報はそのままとし、ボディ部分については その最初と最後の行だけでよく、途中は不必要。
問題-2
問題-3
GET を HEAD で置き換えたリクエストを送るだけである。
telnetを使って、Webサーバにあるファイルに関するサーバヘッダを取得してみ よ。具体的には、問題-1、問題-2 で試してみたURLに関するサーバヘッダを取得 してみよ。ここでは、情報システム学科のWebサーバを使うことにする。
次のプログラム getHtml0.java は、指定したWebサーバのホスト名と取得したいHTMLファイルを引数で指定して、Webサーバからのレスポンスを標準出力に表示するプログラムである。
import java.net.*;
import java.io.*;
public class getHtml0 {
private static final int HTTP_port = 80;
public static void main (String args[]) {
String host= args[0];
String filepath = args[1];
String line;
PrintWriter networkOut = null; //(準備)ソケットへの書き出し
BufferedReader networkIn = null; //(準備)ソケットから読み出し
try{
Socket http = new Socket(host, HTTP_port);
networkIn = new BufferedReader(
new InputStreamReader(http.getInputStream(), "Shift_JIS"));
// new InputStreamReader(http.getInputStream(), "EUC_JP"));
networkOut = new PrintWriter(http.getOutputStream());
System.out.println("Connected to HTTP server " + host + "......");
networkOut.print("GET " + filepath + " HTTP/1.1\n");
networkOut.print("HOST: " + host + "\n");
networkOut.print("\r\n\r\n");
networkOut.flush();
while ((line = networkIn.readLine()) != null) {
System.out.print(line + "\n");
}
} // end of try
catch (IOException e) {
System.out.println("IOエラー発生");
System.err.println(e);
}
finally {
try {
if (networkIn != null)
networkIn.close();
if (networkOut != null)
networkOut.close();
}
catch (IOException e) {}
}
} // end of main
}
たとえば、Webサーバが動いているホスト www.edu.tuis.ac.jp のドキュメントルートにあるテキストファイル index.html を取得するには次のように getHtml0.java を使う。
% java getHtml0 www.edu.tuis.ac.jp /index.htmlプログラム getHtml0.java の説明:
String host= args[0];
String filepath = args[1];
によって、それぞれ文字列変数 host と filepath に格納される。
ポート番号は
private static final int HTTP_port = 80;
で定数化してあり、
Socket http = new Socket(host, HTTP_port);
によって、ホスト名とポート番号(80番)を与えてTCPソケットを開いている。
さらに、
networkIn = new BufferedReader(
new InputStreamReader(http.getInputStream()));
networkOut = new PrintWriter(http.getOutputStream());
で、入出力ストリームの生成とソケットへの結びつけを行っている。
これで、HTTP通信の準備ができた。なお、ここでは、レスポンスメッセージの一部
であるHTML文章の文字コードをShift_JISで送信することを設定してWriterをオープン
(インスタンスを生成)している。
これ以降では、上のHTTPプロトコルに従った文字列の送受信を行えばよい。
実際、次のように Webサーバに GET 要求のための文字列を送信する。
networkOut.print("GET " + filepath + " HTTP/1.1\n");
networkOut.print("HOST: " + host + "\n");
networkOut.print("\r\n\r\n");
networkOut.flush();
ここで networkOut.flush() では、出力ストリームをフラッシュして、確実に文字列を送信する。
後は while(true) ループ
while ((line = networkIn.readLine()) != null) {
System.out.print(line + "\n");
によって、入力ストリームから1行ずつ読み込んだ文字列 line を表示して改行している。
これで、指定したHTMLファイルを入手して、標準出力に表示することになる。
これらの操作の課程において何らかの例外の発生が予測されるために、全体を構文 try{...} catch(..) {...} の中に入れていることに注意する。
この場合には、 finally {....} 構文も併用している。
問題-4
getHtml0.java を学内WebサーバにあるHTMLファイルを取得するために使ってみよ。
幾つかのHTMLファイルについて試みてみよ。
ただし、報告ではヘッダ情報はそのままとし、ボディ部分についてはその最初と最後の行だけでよく、途中は不必要。
問題-5
getHtml0.java で、自分の書いたHTMLファイルを取得するにはどうすればよいか。
問題-6
GET を HEAD で置き換えたリクエストを送るだけである。
指定したWebサーバにあるファイルに関するサーバヘッダを取得するプログラム getHead.java を書け。
このプログラムを使って、問題-4、問題-5 で試してみたURLに関するサーバヘッダを取得してみよ。