下にソースの一部を表示する。
最初に #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);
}
|
ある程度実用的なプログラムを作成しようとすると、 スレッドとかノンブロッキンング通信を使う必要も 出て来ると思うので、皆さん頑張って下さい。
今回の作業では ここの記事とプログラムが役に立ちました。