C言語でHTTPリクエストしてみた Windows編

Microsoft Visual C++ 2005の「Win32コンソールアプリケーション」でやってみた。
 
winsock2.h辺りでよく解らんエラーが。

1>------ ビルド開始: プロジェクト: http_request, 構成: Debug Win32 ------
1>リンクしています...
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__closesocket@4 が関数 _main で参照されました。
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__recv@16 が関数 _main で参照されました。
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__send@16 が関数 _main で参照されました。
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__connect@12 が関数 _main で参照されました。
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__socket@12 が関数 _main で参照されました。
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__htons@4 が関数 _main で参照されました。
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__inet_ntoa@4 が関数 _main で参照されました。
1>http_request.obj : error LNK2019: 未解決の外部シンボル __imp__gethostbyname@4 が関数 _main で参照されました。
1>D:\mydocument2\Visual Studio 2005\http_request\Debug\http_request.exe : fatal error LNK1120: 外部参照 8 が未解決です。
1>ビルドログは "file://d:\mydocument2\Visual Studio 2005\http_request\http_request\Debug\BuildLog.htm" に保存されました。
1>http_request - エラー 9、警告 0
========== ビルド: 0 正常終了、1 失敗、0 更新、0 スキップ ==========

 
ライブラリを追加する。
これでエラーは出なくなる。
ここでえらく時間食った。
流石にこれは知ってる人じゃないと解らない問題。
もうちょっと初心者に優しくして欲しい。

プロジェクト => ○○のプロパティ => 構成プロパティ => リンカ => 入力 => 追加の依存ファイル = ws2_32.lib

 
ソース。
昨日のLinux用のをWindows用に書き換えた。
Linuxでやってた時はUTF-8だから気にならなかったんだけど、WindowsだとSJISだから大体化ける。
今度、文字コード変換もやってみよう。
 
この辺を参考にした。
 
Geekなぺーじ : TCPを使う(クライアント2、gethostbyname)
http://www.geekpage.jp/programming/winsock/gethostbyname-2.php
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#define BUF_LEN 256

typedef struct {
	char schema[10];
	char domain[255];
	char path[255];
	int port;
} URL;

URL *parseURL(char *url)
{
	URL *obj;
	char *p;
	char *p_domain;
	char *p_path;
	char *p_end;

	obj = (URL *)malloc(sizeof(URL));
	memset(obj, '\0', sizeof(URL));
	p_end = url + strlen(url);
	p = strstr(url, "://");
	if (p) {
		strncpy_s(obj->schema, sizeof(obj->schema), url, p-url);
		p_domain = url+strlen(obj->schema)+3;
		if (p_path = strchr(p_domain, '/')) {
			strncpy_s(obj->domain, sizeof(obj->domain), p_domain, p_path-p_domain);
			strncpy_s(obj->path, sizeof(obj->path), p_path, p_end-p_path);
		} else {
			strncpy_s(obj->domain, sizeof(obj->domain), p_domain, p_end-p_domain);
			strcpy_s(obj->path, sizeof(obj->path), "/");
		}
		if (p = strchr(obj->domain, ':')) {
			obj->port = atoi(p+1);
			*p = '\0';
		}
		if (0<strlen(obj->domain)) {
			return obj;
		}
	}
	return NULL;
}

int main(int argc, char *argv[])
{
	SOCKET s;
	struct hostent *servhost;
	struct in_addr addr;
	struct sockaddr_in server;
	char send_buf[BUF_LEN];
	int i;
	URL *url;
	char buf[BUF_LEN];
	int read_size;
	WSADATA wsaData;

	if (argc<2) {
		printf("usage: %s http://domain/path\n", argv[0]);
		return 1;
	}

	url = parseURL(argv[1]);
	if (url==NULL) {
		printf("Parse error: %s\n", argv[1]);
		return 1;
	}

	WSAStartup(2 , &wsaData);
	servhost = gethostbyname(url->domain);
	if (servhost == NULL) {
		printf("IP変換失敗: %s\n", url->domain);
		return 1;
	}

	printf("servhost->h_name: %s\n", servhost->h_name);
	for (i=0; servhost->h_aliases[i]; i++) {
		printf("servhost->h_aliases[%u]: %s\n", i, servhost->h_aliases[i]);
	}
	printf("servhost->h_addrtype: %u\n", servhost->h_addrtype);
	printf("servhost->h_length: %u\n", servhost->h_length);
	for (i=0; servhost->h_addr_list[i]; i++) {
		memcpy(&addr, servhost->h_addr_list[i], 4);
		printf("servhost->h_addr_list[%u]: %s\n", i, inet_ntoa(addr));
	}
	printf("\n");

	memset(&server, '\0', sizeof(server));
	server.sin_family = AF_INET;
	memcpy(&server.sin_addr, servhost->h_addr, servhost->h_length);
	server.sin_port = htons(80);

	// ソケット作成
	if ( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		printf("ソケット作成失敗\n");
		return 1;
	}

	// 接続
	if (connect(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
		printf("接続失敗\n");
		return 1;
	}

	// write
	sprintf_s(send_buf, sizeof(send_buf), "GET %s HTTP/1.1\r\n", url->path);
	send(s, send_buf, (int)strlen(send_buf), 0);

	sprintf_s(send_buf, sizeof(send_buf), "host: %s\r\n", url->domain);
	send(s, send_buf, (int)strlen(send_buf), 0);

	sprintf_s(send_buf, sizeof(send_buf), "\r\n");
	send(s, send_buf, (int)strlen(send_buf), 0);

	// read
	while (1) {
		memset(buf, '\0', BUF_LEN);
		read_size = recv(s, buf, BUF_LEN-1, 0);
		if (0<read_size) {
			printf(buf);
		} else {
			break;
		}
	}

	closesocket(s);
	free(url);
	WSACleanup();

	return 0;
}