HTTPクライアントの作成(TCPクライアントサンプル)

ここでは、クライアントの例としてインチキHTTPクライアントを作ります。 HTTPは日ごろ良く使っていて、馴染みも深いと思います。 ただし、ここで紹介するインチキHTTPクライアントはHTTPメッセージを表示するだけの簡単なものです。

HTTPクライアントサンプル

以下にインチキHTTPクライアントを示します。


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int
main(int argc, char *argv[])
{
 struct sockaddr_in server;
 int sock;
 char buf[32];
 char *deststr;
 unsigned int **addrptr;

 if (argc != 2) {
	 printf("Usage : %s dest\n", argv[0]);
	 return 1;
 }
 deststr = argv[1];

 sock = socket(AF_INET, SOCK_STREAM, 0);
 if (sock < 0) {
	 perror("socket");
	 return 1;
 }

 server.sin_family = AF_INET;
 server.sin_port = htons(80); /* HTTPのポートは80番です */
 server.sin_len = sizeof(server);

 server.sin_addr.s_addr = inet_addr(deststr);
 if (server.sin_addr.s_addr == 0xffffffff) {
	 struct hostent *host;

	 host = gethostbyname(deststr);
	 if (host == NULL) {
		 if (h_errno == HOST_NOT_FOUND) {
			 /* h_errnoはexternで宣言されています */
			 printf("host not found : %s\n", deststr);
		 } else {
			/*
			HOST_NOT_FOUNDだけ特別扱いする必要はないですが、
			とりあえず例として分けてみました
			*/
			printf("%s : %s\n", hstrerror(h_errno), deststr);
		 }
		 return 1;
	 }

	 addrptr = (unsigned int **)host->h_addr_list;

	 while (*addrptr != NULL) {
		 server.sin_addr.s_addr = *(*addrptr);

		 /* connect()が成功したらloopを抜けます */
		 if (connect(sock,
				(struct sockaddr *)&server,
				sizeof(server)) == 0) {
			break;
		 }

		 addrptr++;
		 /* connectが失敗したら次のアドレスで試します */
	 }

	 /* connectが全て失敗した場合 */
	 if (*addrptr == NULL) {
		 perror("connect");
		 return 1;
	 }
 } else {
	 if (connect(sock,
                     (struct sockaddr *)&server, sizeof(server)) != 0) {
		 perror("connect");
		 return 1;
	 }
 }

 /* HTTPで「/」をリクエストする文字列を生成 */
 memset(buf, 0, sizeof(buf));
 snprintf(buf, sizeof(buf), "GET / HTTP/1.0\r\n\r\n");

 /* HTTPリクエスト送信 */
 int n = write(sock, buf, (int)strlen(buf));
 if (n < 0) {
	 perror("write");
	 return 1;
 }

 /* サーバからのHTTPメッセージ受信 */
 while (n > 0) {
	 memset(buf, 0, sizeof(buf));
	 n = read(sock, buf, sizeof(buf));
	 if (n < 0) {
		 perror("read");
		 return 1;
	 }

	 /* 受信結果を標準出力へ表示(ファイルディスクリプタ1は標準出力) */
	 write(1, buf, n);
 }

 close(sock);

 return 0;
}

折角なので、作成したHTTPクライアントを使ってみたいと思います。 www.google.co.jpに接続すると以下のようになります。 (ただし、下記例では表示スペースに押し込むために一部結果を削ってあります。何となくこんな感じかなぁ程度に見てください。)


username$ a.out www.google.co.jp
HTTP/1.0 302 Found
Location: http://www.google.co.jp/cxfer?c=PREF%3D:TM%3D1105:S%3DrItK7m&prev=/
Set-Cookie: PREF=ID=04f0a2d0a3400510:CR=1:TM=110515:LM=1105515:S=55PyTj
S-5evTiH; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html
Server: GWS/2.1
Content-Length: 217
Date: Mon, 10 Jan 2005 04:48:35 GMT
Connection: Keep-Alive

<HTML><HEAD><TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/cxfer?c=PREF%3D:TM%315:S%3D6Gm&prev=/">here</A>.
</BODY></HTML>