下にソースの一部を表示する。
最初に #define で Windows 7 以降のプラットフォームであることを指定する。
これをしないと呼び出せない関数があるためである。
次に winsock2.h と ws2tcpip.h をインクルードする。
なを、GUIプログラムの場合は windows.h をインクルードする訳だが、
winsock2.h の後にインクルードする。
そうしないとwindows.hの中で、winsock.hが呼ばれるので、
旧い Winsock の設定が有効になってまずいことになる(らしい)。
そして プログラムの最初に WSAStartup を読んで Winsock ライブラリーの初期化を行う。
//** Windows 7 以降 #define _WIN32_WINNT _WIN32_WINNT_WIN7 #include <stdio.h> #include <stdlib.h> #include <winsock2.h> #include <ws2tcpip.h> //#include <windows.h> (中略) int main(void) { int ec; WSADATA wsaData; ec=WSAStartup(WINSOCK_VERSION, &wsaData); if(ec){ printf("Winsock の初期化に失敗しました %d\n",ec); return ec; } printf("<<%s:%s %x %x>>\n",wsaData.szDescription,wsaData.szSystemStatus ,wsaData.wVersion,wsaData.wHighVersion); if(server) testServer();else testClient(); WSACleanup(); return EXIT_SUCCESS; } |
うまくゆけば、その環境で使えるアドレス情報のリストが得られる。
あとはそのアドレス情報からソケットを作成する。
SOCKET createSocket() { SOCKET xsock; ADDRINFOW hints; wchar_t wport[1000],whost[1000]; char buf[100]; int ec; memset(&hints, 0, sizeof(hints)); hints.ai_flags=AI_CANONNAME; if(server) hints.ai_flags|=AI_PASSIVE; hints.ai_family = IPv6 ? AF_INET6:AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; MultiByteToWideChar(CP_UTF8, 0, host, -1, whost, 1000); sprintf(buf,"%d",port); MultiByteToWideChar(CP_UTF8, 0, buf, -1, wport, 100); ec= GetAddrInfoW(whost,wport, &hints, &aiList); if(ec) { ec=WSAGetLastError(); printf("GetAddrInfo のエラー %x",ec); return INVALID_SOCKET; } xsock = socket(aiList->ai_family, aiList->ai_socktype, aiList->ai_protocol); if(xsock==INVALID_SOCKET){ ec=WSAGetLastError(); FreeAddrInfoW(aiList); printf("ソケットの作成に失敗しました %x\n",ec); } return xsock; } |
次に listen でクライアントからの受付を開始する。
accept クライアントからの要求で作成された socket を取得する。
以降はこのsocket でクライアントと通信する。
今回は send でメッセージの送信を行なっている。
void testServer() { SOCKET sock=createSocket(),asock; struct sockaddr_in6 adr; SOCKADDR_STORAGE client; int ec,adrSize = sizeof(client); const char* msg="I am Server!"; if(sock==INVALID_SOCKET) return; memset(&adr,0,sizeof(adr)); memcpy(&adr,aiList->ai_addr,4); ec=bind(sock,(sockaddr*)&adr, (int)aiList->ai_addrlen); if(ec){ ec=GetLastError(); printf("bind error %d\n",ec); goto term;} ec=listen(sock,SOMAXCONN); if(ec){ ec=GetLastError(); printf("listen error %d ",ec); goto term; } for(int i=0;i<3;i++){ printf( "クライアントからの接続をまってます\n" ); asock=accept(sock,(SOCKADDR *)&client , &adrSize); if(asock==INVALID_SOCKET){ ec=GetLastError(); printf("accept error %d\n",ec); goto term;; } printf( "クライアントからの接続を受け付けました。メッセージを送信します\n" ); ec=send(asock,msg,strlen(msg),0); if(ec==SOCKET_ERROR){ ec=WSAGetLastError(); printf("送信 error %d\n",ec); goto term; } closesocket(asock); } printf( "サーバーを終了します。\n" ); term:; FreeAddrInfoW(aiList); closesocket(sock); } |
void testClient() { SOCKET sock=createSocket(); int ec; char buf[110]; if(sock==INVALID_SOCKET) return; ec=connect(sock, aiList->ai_addr, aiList->ai_addrlen); if(ec==SOCKET_ERROR){ ec=WSAGetLastError(); printf("接続のエラー %d\n",ec); goto term; } ec=recv(sock,buf,100,0); if(ec==SOCKET_ERROR){ ec=WSAGetLastError(); printf("読込のエラー %d\n",ec); goto term; } buf[ec]=0; printf("受信しました [%s]\n",buf); term:; FreeAddrInfoW(aiList); closesocket(sock); } |
ある程度実用的なプログラムを作成しようとすると、 スレッドとかノンブロッキンング通信を使う必要も 出て来ると思うので、皆さん頑張って下さい。
今回の作業では ここの記事とプログラムが役に立ちました。