HTTPのバージョン違いによるクライアント作成時のハマりどころ
C言語のソケットプログラミングの勉強にと、HTTPクライアントを書いていたら、HTTPのバージョンによる動作の違いに少しハマりました*1。以下のような簡単なリクエストを送信し、結果を受信して標準出力に書き出すだけのプログラムです。
GET / HTTP/1.1 Host: www.google.co.jp:80
そして、実際に動作させてみるとページのデータは取得できるものの、受信ループから抜けられない、という結果になりました*2。しばらく頭をひねったのですが、HTTPのバージョンを1.0に変更するか、リクエスト行に「Connection: close」を追加することで解決しました。道理で世の中のサンプルプログラムの多くはHTTP/1.0で書かれているわけです。
これは、HTTP/1.1でリクエストごとに接続が終了しないように変更されたためで、切断するにはサーバかクライアントのどちらかが「Connection: close」を指定する必要があります。HTTP/1.0では、クライアント・サーバがKeep-Aliveをサポートしている場合以外は必ずリクエストごとに切断されるようです。
要するに、今回の本質的な原因は、「バージョンの数字が大きい方がエライと思い込んで勝手に書き換えた」ことでしょう。先にHTTPの勉強しておくべきでした。
以下、動作サンプル用のRubyコードです。HTTPのバージョンの数字やConnectionの項目を切り替えてご確認どうぞ。
# Pull down Google's web page require 'socket' include Socket::Constants socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.co.jp' ) socket.connect( sockaddr ) socket.write( "GET / HTTP/1.1\r\n" ) socket.write( "Host: www.google.co.jp\r\n" ) #socket.write( "Connection: close\r\n" ) socket.write( "\r\n" ) results = socket.read puts results
追記
受信データを出力するだけじゃなく利用する場合はchunkedエンコーディングについても理解する必要があります。