[[Net002]]

* Windows 版単純な client program [#cc99b255]
* Windows版単純な client program [#cc99b255]
前節の単純な clinet program の Windows 版を書いてみる。Windows の場合、socket library は WINSOCK2 と呼ばれている通常の DLL(Dynamic Link library) として提供されている。Library interface は ws2_32.lib である。

開始時に WSAStartup 関数を呼び出して、library を(dynamic に)load し、終了時に WSACleanup 関数を呼び出して解放する必要がある点を除けば、ほぼ同じである。

違いは、
- socket が socket descriptor ではなく socket handle として表現されてこと(ただし両者とも int で表現されているので元のソースのままでも動く)
- socket 関数が失敗した時の戻り値が INVALID_SOCKET であること(実はこれも実体は -1 であるので元のソースのままでも動く)
- connect 関数が失敗した時の戻り値が SOCKET_ERROR であること(実はこれも実体は -1 であるので元のソースのままでも動く)
- close ではなく closesocket を使う
- error code の取得が WSAGetLastError 関数の呼び出しによること

といったところである。

なお、getaddrinfo 関数を使うには、_WIN32_WINNT が 0x0501 以上である必要がある。従って 自動的に設定されない場合は compile 時に _WIN32_WINNT を設定する必要がある。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <winsock2.h>
 #include <ws2tcpip.h>
 
 #define MY_BUFSIZE 1024
 static char buf[MY_BUFSIZE];
 
 int main(int argc, char* argv[])
 {
 	struct sockaddr_in saddr;
 	struct sockaddr_in* resaddr;
 	struct addrinfo hints;
 	struct addrinfo* res;
 	SOCKET sd;
 	int err;
 	int port;
 	const char* host;
 	size_t nrecv;
 	size_t n;
 
 	WORD wReqVersion;
 	WSADATA wsa;
 
 	/* Start the WinSock library */
 	wReqVersion = MAKEWORD(2,2);
 	if((err = WSAStartup(wReqVersion, &wsa)) != 0)
 		return err;
 	if((LOBYTE(wsa.wVersion) != 2) ||
 	   (HIBYTE(wsa.wVersion) != 2))
 	{
 		WSACleanup();
 		return (-1);
 	}
 	
 	/* Check the command line */
 	if((argc != 2) && (argc != 3))
 	{
 		fprintf(stderr, "Usage: %s host [port]\n", argv[0]);
 		WSACleanup();
 		return (-1);
 	}
 
 	/* Set the hostname and port number */
 	res = 0;
 	port = 80;
 	host = argv[1];
 	if(argc == 3)
 	{
 		port = atoi(argv[2]);
 		if(port <= 0)
 		{
 			fprintf(stderr, "Illegal port number (%d)\n", port);
 			WSACleanup();
 			return (-1);
 		}
 	}
 
 	/* Setup the address */
 	memset(&saddr, 0, sizeof(saddr));
 	memset(&hints, 0, sizeof(hints));
 
 	hints.ai_family = AF_INET;
 	hints.ai_socktype = 0;
 	hints.ai_protocol = 0;
 	if((err = getaddrinfo(host, 0, &hints, &res)) != 0)
 	{
 		WSACleanup();
 		return err;
 	}
 	resaddr = (struct sockaddr_in*)res->ai_addr;
 	saddr.sin_family = AF_INET;
 	saddr.sin_port = htons((u_short)port);
 	saddr.sin_addr = resaddr->sin_addr;
 	freeaddrinfo(res);
 
 	/* Create socket */
 	if((sd = socket( PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
 	{
 		err = WSAGetLastError();
 		WSACleanup();
 		return err;
 	}
 
 	/* Connect to the host */
 	if(connect(sd, (const struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR)
 	{
 		err = WSAGetLastError();
 		WSACleanup();
 		return err;
 	}
 
 	/* Send the http request */
 	send(sd, "GET / HTTP/1.0\r\n\r\n", 18, 0);
 
 	/* Receive until connection closed */
 	while((nrecv = recv(sd, buf, MY_BUFSIZE, 0)) > 0)
 	{
 		for(n = 0; n < nrecv; n++)
 			fputc((int)buf[n], stdout);
 	}
 
 	/* Close our socket */
 	closesocket(sd);
 	WSACleanup();
 	return 0;
 }

上の source を n03.c という名前のファイルに保存したとすると、compile/link は

MinGW の場合は、
 C:\>gcc -Wall -D_WIN32_WINNT=0x0501 n03.c -lws2_32

とする。

Microsoft Visual C++ の場合は、
 C:\>cl /W3 /EHsc /D_WIN32_WINNT=0x0501 n03.c ws2_32.lib

とする。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS