という感じになります。
- ソケットの作成を行う。
- 受信ポートを指定する。
- NTPサーバにパケットを送信する。
- NTPサーバから時刻の情報を受信する。
- ソケットを破棄する。
select関数は、ソケットの状態を調べる関数です。
複数のソケットを扱うときに、どのソケットに受信データがあるかなどを調べられます。
/* 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; } /* ソケットを作成する処理 */ /* UDPモードでsocにソケットを作成します */ soc = socket(PF_INET, SOCK_DGRAM, 0); if(soc == INVALID_SOCKET){ fprintf(stderr,"Error: Socket作成失敗\n"); return; } /* 受信ポートを指定する処理 */ /* ソケットのアドレスの構造体にサーバのIPアドレスとポート番号を設定します */ sockname.sin_family = AF_INET; /* インターネットの場合 */ sockname.sin_addr.s_addr = INADDR_ANY; /* 自分のIPアドレスを使うようにする */ sockname.sin_port = htons((unsigned short)local_port); /* 受信するポート番号 */ memset(sockname.sin_zero,(int)0,sizeof(sockname.sin_zero)); if(bind(soc,(struct sockaddr *)&sockname,sizeof(sockname)) == SOCKET_ERROR){ fprintf(stderr,"受信ポート番号の指定に失敗\n"); } /* サーバの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)); /* サーバにパケットを送信する処理 */ /* NTPパケットをSNTP用に初期化する */ NTP_Send.Control_Word = htonl(0x0B000000); NTP_Send.root_delay = 0; NTP_Send.root_dispersion = 0; NTP_Send.reference_identifier = 0; NTP_Send.reference_timestamp = 0; NTP_Send.originate_timestamp = 0; NTP_Send.receive_timestamp = 0; NTP_Send.transmit_timestamp_seconds = 0; NTP_Send.transmit_timestamp_fractions = 0; /* サーバを指定してNTPパケットを送信する */ if(sendto(soc,(const char *)&NTP_Send, sizeof( NTP_Send ),0,(struct sockaddr *)&serversockaddr,sizeof(serversockaddr)) == SOCKET_ERROR){ fprintf(stderr,"Error: サーバへの送信失敗\n"); /* ソケットを破棄する */ closesocket(soc); return; } /* タイムアウトを行う処理 */ /* select関数を使ってタイムアウトを設定する */ waittime.tv_sec = TIMEOUT; /* タイムアウト秒数を設定する */ waittime.tv_usec = 0; FD_ZERO(&rdps); /* 初期化する */ FD_SET(soc,&rdps); /* selectするソケットを追加する */ selret = select(FD_SETSIZE,&rdps,(fd_set *)0,(fd_set *)0,&waittime); if(selret == SOCKET_ERROR){ /* エラーの場合 */ fprintf(stderr,"Error: サーバからの受信失敗\n"); /* ソケットを破棄する */ closesocket(soc); return; } if(selret == 0){ /* タイムアウトの場合 */ fprintf(stderr,"Error: タイムアウトしました\n"); /* ソケットを破棄する */ closesocket(soc); return; } if(FD_ISSET(soc,&rdps) == FALSE){ /* 受信はしたが、指定のソケットではない場合 */ fprintf(stderr,"Error: サーバからの受信失敗\n"); /* ソケットを破棄する */ closesocket(soc); return; } /* サーバから時刻情報を受信する処理 */ /* サーバを指定して受信を行う */ sockaddr_Size = sizeof(serversockaddr); if(recvfrom(soc, (char *)&NTP_Recv, sizeof(NTP_Recv), 0,(struct sockaddr *)&serversockaddr,&sockaddr_Size) == SOCKET_ERROR ){ fprintf(stderr,"Error: サーバからの受信失敗\n"); /* ソケットを破棄する */ closesocket(soc); return; } /* ソケットを破棄する処理 */ /* ソケットを破棄する */ closesocket(soc);
sntpc00.zipこのプログラムはコンソールで動作します。
- sntpc.c
- sntpc.exe