/* * name: httpget version 0.1 * use: TCP/IP socket client sample program for Linux * date: Tue Jul 17 2001 * author: itouh@lycos.ne.jp */ #include <stdio.h> //fprintf(), stderr #include <unistd.h> //write(), close() #include <sys/types.h> //socket(), connect(), send(), recv() #include <sys/socket.h> //socket(), connect(), send(), recv() #include <netdb.h> //gethostbyname(), struct hostent #include <netinet/in.h> //htons(), struct in_addr #define MAXBUF 1500 #define HTTP_SERVER_PORT 80 #define HOSTNAME "www.ibrado.com" #define FILE_PATH "/sock-faq/index.html" #define USER_AGENT "Mozilla/4.0 (compatible; httpget 0.1; Linux)" /* func prototype */ void host2addr(const char *hostname, struct in_addr *addr); void errexit(char *s); int main(void){ struct sockaddr_in addr; //接続先のIPアドレスとポート番号を格納する unsigned char buf[MAXBUF]; int rc; //result code int sock; //file descripter /* サーバのHOSTNAME文字列を IPアドレスに変換して、構造体に格納する */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(HTTP_SERVER_PORT); host2addr(HOSTNAME, &addr.sin_addr); /* ソケットを生成する */ sock = socket(AF_INET, SOCK_STREAM, 0); if(sock < 0) errexit("unable to generate a socket"); /* ソケットを介して、サーバと接続する */ rc = connect(sock, (struct sockaddr *)&addr, sizeof(addr)); if(rc != 0) errexit("unable to connect"); /* サーバに HTMLファイル送出を要求する */ { char s[MAXBUF]; memset(s, 0x00, MAXBUF); sprintf(s, "GET %s HTTP/1.0\r\n" "User-Agent: %s\r\n" "Host: %s\r\n" "Connection: close\r\n\r\n", FILE_PATH, USER_AGENT, HOSTNAME); rc = send(sock, s, strlen(s), 0); if(rc < 0) errexit("unable to send"); } /* データを受信する */ for(;;){ memset(buf, 0x00, MAXBUF); rc = recv(sock,buf,sizeof(buf),0); if(rc < 0) errexit("unable to receive data correctly"); else if(rc == 0) break; //データ受信完了 write(1, buf, rc); //標準出力 stdout に出力する } close(sock); /* ソケットを閉じる */ fprintf(stderr, "\n\nhttpget: Receiving data is completed.\n"); return 0; } /* * host文字列を IPアドレスに変換して、in_addr構造体に格納する */ void host2addr(const char *hostname, struct in_addr *ip){ struct hostent *host; host = gethostbyname(hostname); if(host != NULL){ *ip = *(struct in_addr *)(host->h_addr_list[0]); return; } errexit("unable to locate the server\n"); } /* * エラーメッセージを表示して終了する */ void errexit(char *s){ fprintf(stderr, "error: %s\n", s); exit(1); }
コンパイル、実行は、
$ cc -o httpget httpget.c $ ./httpget | lessとすればいいでしょう。 VineLinux2.1.5で動作を確認しました。
#define HTTP_SERVER_PORT 80 #define HOSTNAME "www.ibrado.com" #define FILE_PATH "/sock-faq/index.html"ここでは、www.ibrado.com のサイトのポート80番 (一般的にはHTTPサーバ) につないて、/sock-faq/index.html というファイルを要求しようとしてます。URL でいえば、http://www.ibrado.com/sock-faq/index.html のファイル。
手順としてはまず、「www.ibrado.com」というホストネームを、IPアドレスに変換します。そのためには DNSサーバにアクセスしなくてはなりませんが、C言語では gethostbyname() を使えばいいです。
そのIPアドレスと、ポート番号 ( htons でネットワークバイトオーダに変換しておきます)、そしてアドレスファミリ (インターネットに接続する場合は AF_INET でいい)を、sock_addr_in構造体に代入します。この構造体の中身は、man ip で調べることができます。
ソケットを生成します。そのソケットを使用して、サーバと接続。HTTPプロトコルにのっとって、文字列を送り、「ファイルを送ってくれたまえ」と要求します。
データを受信して、全部受けとったらソケットを閉じます。 これが HTTPプロトコルでファイルを取得する流れです。1ファイルごとにこの手順をふまなければなりません (IPアドレス調べて構造体に代入するとかの手順は、同じサイトに接続するときは省いてよし)。