Internet Programming

HTTPクライアントの作成(同期型)

[1997/11/28]

実際にTCPクライアントを作成する例として、HTTPクライアントを作成してみます。
HTTPは、WebサーバからHTMLなどを取得するプロトコルです。
HTTP(Hypertext Transfer Protocol)についての詳細は、RFC 1945(HTTP1.0)、RFC 2068(HTTP1.1)を参照してください。

HTTPクライアントの流れは、
  1. ソケットの作成を行う。

  2. Webサーバに接続する。

  3. Webサーバに"GET"リクエストを行う。

  4. Webサーバから送信されたデータをすべて受信する。

  5. ソケットを破棄する。
という感じになります。

HTTPでは、クライアントがリクエストを送ると、Webサーバはデータを送信して送信が終わると切断するので、クライアントはすべて受信してしまえばソケットを破棄します。

以下のソースは、サンプル中の実際にWebサーバと接続してデータを取得する部分です。
見て分かるとおり、「TCPクライアントの作成手順」で紹介したAPIしか使っていません。


/* WinSockの初期化を行う処理 */
	/* WinSockの初期化を行う */
	wVersionRequested = MAKEWORD(1,1);			/* バージョン 1.1 を要求する */
	nErrorStatus = WSAStartup(wVersionRequested,&wsaData);
	if(atexit((void (*)(void))(WSACleanup))){		/* 終了時にWinSockのリソースを解放するようにしておく */
		fprintf(stderr,"Error: atexit(WSACleanup)失敗\n");
		return;
	}
	if(nErrorStatus != 0){
		fprintf(stderr,"Error: WinSockの初期化失敗\n");
		return;
	}

/* ソケットを作成する処理 */
	/* socにソケットを作成します */
	soc = socket(PF_INET, SOCK_STREAM, 0);
	if(soc == INVALID_SOCKET){
		fprintf(stderr,"Error: Socket作成失敗\n");
		return;
	}

/* サーバのIPアドレスを取得する処理 */
	/* svNameにドットで区切った10進数のIPアドレスが入っている場合、serveraddrに32bit整数のIPアドレスが返ります */
	serveraddr = inet_addr((char*)svName);
	if(serveraddr == -1){
		/* サーバ名(svName)からサーバのホスト情報を取得します */
		serverhostent = gethostbyname(svName);
		if(serverhostent == NULL) {
			fprintf(stderr,"Error: ホストアドレス取得失敗\n");
			/* ソケットを破棄する */
			closesocket(soc);
			return;
		}else{
			/* サーバのホスト情報からIPアドレスをserveraddrにコピーします */
			serveraddr = *((unsigned long *)((serverhostent->h_addr_list)[0]));
		}
	}

/* サーバに接続する処理 */
	/* サーバのアドレスの構造体にサーバのIPアドレスとポート番号を設定します */
	serversockaddr.sin_family	 = AF_INET;			/* インターネットの場合 */
	serversockaddr.sin_addr.s_addr  = serveraddr;			/* サーバのIPアドレス */
	serversockaddr.sin_port	 = htons((unsigned short)port);	/* ポート番号 */
	memset(serversockaddr.sin_zero,(int)0,sizeof(serversockaddr.sin_zero));
	/* サーバへ接続します */
	if(connect(soc,(struct sockaddr *)&serversockaddr,sizeof(serversockaddr)) == SOCKET_ERROR){
		fprintf(stderr,"Error: サーバへの接続失敗\n");
		/* ソケットを破棄する */
		closesocket(soc);
		return;
	}

/* サーバに GET リクエストを送る処理 */
	/* サーバに GET リクエストを送信します */
	/* 送信した文字列はサーバに届きます */
	sprintf(sendbuf,"GET %s HTTP/1.0\r\nHost: %s:%d\r\nUser-Agent: httpc/0.0\r\n\r\n",html,svName,port);	/* リクエストヘッダを作成する */
	if(send(soc,sendbuf,strlen(sendbuf),0) == SOCKET_ERROR){
		fprintf(stderr,"Error: サーバへの送信失敗\n");
		/* 送受信を無効にする */
		shutdown(soc,2);
		/* ソケットを破棄する */
		closesocket(soc);
		return;
	}

/* サーバからデータを受信する処理 */
	/* サーバからデータをすべて受信し終わるまで繰り返す */
	while(1){
		/* サーバからデータを受信します */
		buf_len = recv(soc,recvbuf,RECVSIZE - 1,0);	/* 受信失敗の場合 */
		if(buf_len == SOCKET_ERROR){
			fprintf(stderr,"Error: サーバからの受信失敗\n");
			break;
		}else if(buf_len == 0){			/* 受信終わり */
			break;
		}
		recvbuf[buf_len] = '\0';		/* 受信バッファの後ろにヌル文字を付加する */
		printf("%s",recvbuf);		/* 標準出力する */
	}

/* ソケットを破棄する処理 */
	/* 送受信を無効にする */
	shutdown(soc,2);
	/* ソケットを破棄する */
	closesocket(soc);



サンプルのダウンロード:

httpc00.zip
- httpc.c
- httpc.exe
このプログラムはコマンドプロンプトで動作します。

httpc.cをコンパイルする場合は、wsock32.lib をリンクしてください。

サンプルの前半は、引数で渡されたURLからサーバ名と取得するページを分割しています。
後半で、Webサーバに接続してページをGETしています。



mail
メールアドレス
<nakka@nakka.com>


Internet Programming
Internet Programming