HTTPでファイルを取得するには?


BackUptyuu  2003-04-21 14:57:38  No: 51319  IP: [192.*.*.*]

こんにちは。BackUptyuuと申します。
現在、WindowsでHTTPで、ホームページなどのファイル(HTMLやGIF)
を取得するプログラムを作成しようと考えています。
ホームページにアクセスするにはwinsock.hのconnectを使えばいいと
いうところまでわかったのですが、その先がわかりません。
ファイルを取得するにはどういった関数とヘッダファイルが必要なの
か教えてください。

編集 削除
YuO  2003-04-21 15:20:34  No: 51320  IP: [192.*.*.*]

> 現在、WindowsでHTTPで、ホームページなどのファイル(HTMLやGIF)
> を取得するプログラムを作成しようと考えています。
> ホームページにアクセスするにはwinsock.hのconnectを使えばいいと
> いうところまでわかったのですが、その先がわかりません。
> ファイルを取得するにはどういった関数とヘッダファイルが必要なの
> か教えてください。

WinSock関連の関数で十分です。

簡単に手順を書くと,
1. TCPソケットを作る(socket)
2. サーバーに接続する(connect)
3. リクエストを送信する(send)
4. レスポンスを受信する(recv)
5. 接続を切断する(shutdown)
6. ソケットを閉じる(closesocket)
となります。

リクエスト,レスポンスの詳細は
RFC 1945 Hypertext Transfer Protocol -- HTTP/1.0.
http://www.ietf.org/rfc/rfc1945.txt
RFC 2616 Hypertext Transfer Protocol -- HTTP/1.1.
http://www.ietf.org/rfc/rfc2616.txt
などを参照してください。

編集 削除
BackUptyuu  2003-04-23 12:56:11  No: 51321  IP: [192.*.*.*]

こんにちは。YuOさん。
ここ数日悩みながらいろいろ調べたのですが結局わかりませんでした。
受信のところでrecv()とありますが、ここで第二引数で渡している変数
に受信データを格納するのでしょうか?
受信したファイルをどこかに保存するようなサンプルがあったらいいの
ですが、見つかりません。
これも教えていただけないでしょうか?

編集 削除
YuO  2003-04-23 13:17:28  No: 51322  IP: [192.*.*.*]

int recv (
  SOCKET s,
  char * buf,
  int len,
  int flags
);

s : 受信対象となるソケット。
buf : 受信したデータを格納するためのバッファ。
len : バッファbufの大きさ。
flags : 受信方法を決めるフラグ。通常は0。

です。

でもって,保存するにはbufを適当に処理して,
#HTTPヘッダがあるため
fwriteなりWriteFileなりbasic_ostream::writeなりでファイルに書き込むだけです。
受信さえできれば保存は特別問題はないと思うのですが……。

編集 削除
BackUptyuu  2003-04-24 09:50:32  No: 51323  IP: [192.*.*.*]

おはようございます。
解決しました。!
ただし、テキストファイルに関してです。
テキストファイルを処理する方法はわかったのですが、
バイナリファイル(GIF、JPG)に関する処理方法が
わかりません。テキストファイルとは違う処理をする
のでしょうか?
やったのは、recvで取得したバッファを1行だけ除いて
あとはファイルに書き込むです。
バイナリファイルの場合ファイルオープンは"wb"モード
で開いています。
どうすればいいのでしょうか?

編集 削除
YuO  2003-04-24 18:56:38  No: 51324  IP: [192.*.*.*]

> テキストファイルを処理する方法はわかったのですが、
> バイナリファイル(GIF、JPG)に関する処理方法が
> わかりません。テキストファイルとは違う処理をする
> のでしょうか?

特別な処理はないです。
本体部分を全てバイナリでファイルに書き込めばいいだけですから。
あとは,それを「テキストファイルである」として読むソフトウェアにとってはテキストファイルに,
「バイナリファイルである」として読むソフトウェアにはバイナリファイルに,
それぞれ見えますから。


> やったのは、recvで取得したバッファを1行だけ除いて
> あとはファイルに書き込むです。

HTTPはそのような構造にはなっていません。
RFCを読み直す必要があります。

編集 削除
BackUptyuu  2003-04-30 16:00:29  No: 51325  IP: [192.*.*.*]

RFCを読みました。
ヘッダ部分はCRLFが2回続くところ(つまり、空行)で終わるようですね。
そこで、CRLFが2回つづくところで切ってそこからデータを書き込むように
しました。
しかし、作成したプログラムでダウンロードしたデータと、インターネット
エクスプローラでダウンロードしたデータで違いが見られます。
今回は、GIFファイルをダウンロードしたのですが、ダウンロードした結果
のファイルの容量とインターネットエクスプローラでダウンロードした結果
のファイルの容量が異なります。
以下は、そのファイルを書き込む部分です。



  SOCKET client;        /* クライアントソケット     */
  int res;          /* 関数の返し値         */
  char buffer[4000];      /* 読み出し用バッファ      */
  FILE * fpgetfile;      /* 受信データを格納するファイル */
  int  ifilejudge;      /* ファイルヘッダか判定     */
  unsigned int  iloopcount;

/*************************途中省略************************/

  /* データの入力 */
  for(/* */;;){
    res = recv(client, buffer, sizeof(buffer), 0);
    if(res == SOCKET_ERROR)  error("Data Reading.");
    if(res == 0)  break;

    if(ifilejudge == 1)
    {
      for(iloopcount = 0; iloopcount < strlen(buffer); iloopcount++)
      {
        if(buffer[iloopcount] == 13 && buffer[iloopcount + 1] == 10 && buffer[iloopcount + 2] == 13 && buffer[iloopcount + 3] == 10)
        {
          fwrite(&buffer[iloopcount + 4], res, 1, fpgetfile);
        }
      }
      /* ファイルヘッダ判定フラグを0にする */
      ifilejudge = 0;
    }
    else
    {
      fwrite(buffer, res, 1, fpgetfile);
    }
  }

編集 削除
YuO  2003-04-30 19:57:14  No: 51326  IP: [192.*.*.*]

> fwrite(&buffer[iloopcount?+?4],?res,?1,?fpgetfile);

これは間違っていますね。
fwrite(buffer + iloopcount + 4, res - 4 - iloopcount, 1, fpgetfile);
だと思います。

でもって,
Content-Lengthヘッダをちゃんと処理しないといけませんよ。

編集 削除