| 前へ << 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 までお願いします。