前へ << HTTP クライアントを作ってみよう(2) | HTTP クライアントを作ってみよう(4) >> 次へ |
クライアント名は…まぁ何でもいいのですが、とりあえず 「httptalker」としましょう。 勉強用のサンプルなのでバージョンは 0.10 とします。 結局 User-Agent として「httptalker/0.10 (HTTP client sample)」を送ることにします。
サーバへの User-Agent の渡し方ですが、
% telnet www.cs.gunma-u.ac.jp 80 Trying 133.8.2.7... Connected to www.cs.gunma-u.ac.jp. Escape character is '^]'. GET / HTTP/1.0(リターン) User-Agent: httptalker/0.10 (HTTP client sample)(リターン) (リターン)と、メソッドの後につづけて User-Agent を送信します。
telnet を使って、proxy.example.com:8080 を経由して http://www.cs.gunma-u.ac.jp/ にアクセスしてみましょう。
% telnet proxy.example.com 8080 Trying 10.11.12.13... Connected to proxy.example.com Escape character is '^]'. GET http://www.cs.gunma-u.ac.jp/ HTTP/1.0(リターン) (リターン)これまでと違うところは、目的の WWW サーバ (この場合はwww.cs.gunma-u.ac.jp) に 直接繋げるのではなく、proxy サーバに接続している点です。ポート番号も 80 ではなく 8080 にします。そして、送信するリクエストの内容が
GET / HTTP/1.0(リターン)ではなく
GET http://www.cs.gunma-u.ac.jp/ HTTP/1.0(リターン)と、URL をそのまま渡しています。proxy.example.com で動いている proxy サーバは、あなたの代わりに www.cs.gunma-u.ac.jp のポート 80 に接続して、
GET / HTTP/1.0(リターン)というリクエストを送るわけです。そして返ってきたデータを あなたのところに送ってくるのです。proxy サーバは「代理サーバ」と 訳される理由がわかりますね。 あなたの代わりに目的のホストに接続してくれるのが proxy サーバなのです。
ヘッダ部分の一番先頭の行はステータスと呼ばれる情報となっており、 そこを見れば「Not Found」「Permission Denied」「Internal Server Error」などの状態を 判断できます。よく知られているのは
HTTP/1.1 200 OK HTTP/1.1 301 Moved Permanently HTTP/1.1 404 Not Found HTTP/1.1 500 Internal Server Errorといったものですが、みなさんもだいたいの意味はわかるでしょう。
GET に比べて HEAD はボディを転送しない分だけ、送受信する データ量は少なくなり、その結果処理にかかる時間も短くてすみます。 そのため、リンク先がつながっているかどうかを調べるための リンクチェッカなどが HEAD メソッドをよく使います。
http://www.cs.gunma-u.ac.jp/ のヘッダ情報だけを受け取るには以下のようにします。
% telnet www.cs.gunma-u.ac.jp 80 Trying 133.8.2.7... Connected to www.cs.gunma-u.ac.jp. Escape character is '^]'. HEAD / HTTP/1.0(リターン) (リターン)
% telnet proxy.example.com 8080 Trying 10.11.12.13... Connected to proxy.example.com Escape character is '^]'. HEAD http://www.cs.gunma-u.ac.jp/ HTTP/1.0(リターン) User-Agent: httptalker/0.10(リターン) (リターン)
httptalker -METHOD URL [Proxy]です。METHOD には GET か HEAD を指定します。URL は http://www.hoge.com/fuga.html などです。Proxy には proxy.example.com:8080 などと指定しますが、省略可能です。 例えば
% ./httptalker -GET http://www.hoge.com/fuga.html % ./httptalker -GET http://www.hoge.com/fuga.html proxy.example.com:8080 % ./httptalker -HEAD http://www.hoge.com/fuga.htmlのように指定します。ソースは以下のようになります。
1: #!/usr/local/bin/perl -w 2: 3: # $Id: http-client-2.pl,v 1.2 2002/02/05 17:53:09 68user Exp $ 4: 5: use Socket; # Socketモジュールを使う 6: 7: #----------------引数解析-------------------- 8: 9: # メソッドを解析。-HEADか-GET以外ならエラー 10: if ( $ARGV[0] eq "-HEAD" || $ARGV[0] eq "-head" ){ 11: $method = "HEAD"; 12: } elsif ( $ARGV[0] eq "-GET" || $ARGV[0] eq "-get" ){ 13: $method = "GET"; 14: } else { 15: print "methodはGETかHEADを指定してください。\n"; 16: exit; 17: } 18: 19: # URLを解析。http://host/pathという形式でなければエラー 20: if ( $ARGV[1] =~ m|^http://([-_\.a-zA-Z0-9]+)/?(.*)$| ){ 21: $host = $1; 22: $path = $2; 23: } else { 24: print "URLは http://host/path という形式で指定してください。\n"; 25: exit; 26: } 27: 28: # 引数が3つあるならProxyを解析 29: if ( $#ARGV == 2 ){ 30: if ( $ARGV[2] =~ m|^([-_\.a-zA-Z0-9]+):(\d+)$| ){ 31: $proxy = $1; 32: $port = $2; 33: $connect_host = $proxy; 34: } else { 35: print "Proxy は host:port という形式で指定してください。\n"; 36: exit; 37: } 38: $connect_host = $proxy; 39: 40: # 引数が2つしかないなら 41: } else { 42: $connect_host = $host; 43: $port = getservbyname('http', 'tcp'); 44: } 45: 46: 47: #----------------接続処理------------------- 48: 49: # ホスト名を、IPアドレスの構造体に変換 50: $iaddr = inet_aton($connect_host) 51: || die "$connect_hostは存在しないホストです。\n"; 52: 53: # portとIPアドレスとまとめて構造体に変換 54: $sock_addr = pack_sockaddr_in($port, $iaddr); 55: 56: # ソケット生成 57: socket(SOCKET, PF_INET, SOCK_STREAM, 0) 58: || die "ソケットを生成できません。\n"; 59: 60: # 指定のホストの指定のportに接続 61: connect(SOCKET, $sock_addr) 62: || die "$connect_host の ポート$portに接続できません。\n"; 63: 64: # ファイルハンドルSOCKETをバッファリングしない 65: select(SOCKET); $|=1; select(STDOUT); 66: 67: 68: #------------HTTPリクエスト送信----------------- 69: 70: # Proxyサーバに接続するなら 71: if ( defined $proxy ){ 72: print SOCKET "$method http://$host/$path HTTP/1.0\r\n"; 73: # 直接WWWサーバに接続するなら 74: } else { 75: print SOCKET "$method /$path HTTP/1.0\r\n"; 76: } 77: 78: # User-Agentを送信 79: print SOCKET "User-Agent: httptalker/0.10 (HTTP client sample)\r\n"; 80: print SOCKET "\r\n"; 81: 82: 83: #------------サーバからのデータを受信 ----------------- 84: 85: if ( $method eq "GET" ){ 86: # GETメソッドならヘッダ部分は表示せず 87: while (<SOCKET>){ 88: m/^\r\n$/ && last; 89: } 90: # ボディ部分だけを表示する 91: while (<SOCKET>){ 92: print $_; 93: } 94: } else { 95: # HEADメソッドなら全文表示 96: while (<SOCKET>){ 97: print $_; 98: } 99: }主な変更点は、引数解析、GET と HEAD の場合分け、Proxy を経由するかどうかの場合分けです。
解説は…書かなくても大丈夫ですよね? 前バージョンと見比べてみれば理解できると思います。
さて、改良はしたものの、まだまだHTTP クライアントとしては不完全です。 次節で問題点を上げますので、各自で改良してみてください。
前へ << HTTP クライアントを作ってみよう(2) | HTTP クライアントを作ってみよう(4) >> 次へ |
ご意見・ご指摘は Twitter: @68user までお願いします。