SNTPで時刻取得

みんなが作った便利な関数やサンプルを共有するコミュニティです。
[url]http://www.activebasic.com/forum/viewforum.php?f=2]ActiveBasicの「実践コードモジュール」[/url]的な感じでやりましょう。
フォーラム(掲示板)ルール
・投稿するコードはできるだけ一つ、もしくは一つの関数を補助する複数の関数の形式にするか、
それだけをコンパイルして動くソースコード一式の形にしてください。
記事には説明だけを書き、コードは添付ファイルにしてもかまいません。
・使い方などの説明も書いてください。
環境に依存するコードの場合は、対象の環境も書いてください。
・使用条件(ライセンスなど)も書いていただけるとありがたいです。
・C言語、もしくはC++推奨ですが、他の言語でもかまいません。
・コードは正しくcodeタグで囲みましょう。
・一つのスレッドで一つのサンプルが基本です。
関連するサンプルの場合はまとめてもかまいません。
・投稿したサンプルを修正する場合には、スレッドの返信の形で投稿してください。
(新しいスレッドにしないでください。記事の編集でもかまいません)
返信
アバター
みけCAT
記事: 6067
登録日時: 8年前
住所: 千葉県
連絡を取る:

SNTPで時刻取得

#1

投稿記事 by みけCAT » 8年前

SNTPを使って時刻を取得するプログラムです。
サーバーのドメインまたはIPアドレスを入力すると時刻を取得して表示します。
「時刻」がローカルの時刻、「結果」がサーバーの時刻です。

コード:

#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <time.h>

/*環境依存*/
#include <limits.h>
#if UCHAR_MAX!=0xff || UINT_MAX!=0xffffffff
#error Variable size can't accepted.
#endif
#if ULONG_MAX!=0xffffffff || ULLONG_MAX!=0xffffffffffffffff
#error Variable size can't accepted.
#endif

typedef struct {
	unsigned int hidword;
	unsigned int lodword;
} rybits;

typedef struct {
	unsigned char seigyo;
	unsigned char kaisou;/*階層*/
	unsigned char bkankaku;/*ボーリング間隔*/
	unsigned char seido;/*精度*/
	unsigned int rdelay;/*ルート遅延*/
	unsigned int rkaku;/*ルート拡散*/
	unsigned int ssikibetu;/*参照識別子*/
	rybits santstamp;/*参照タイムスタンプ*/
	rybits kaitstamp;/*開始タイムスタンプ*/
	rybits rectstamp;/*受信タイムスタンプ*/
	rybits sentstamp;/*送信タイムスタンプ*/
	unsigned int key;/*鍵識別子*/
	rybits md[2];/*メッセージダイジェスト*/
} sntppacket;

int main(void) {
	char servername[1024];
	WSADATA wsa;
	SOCKET sock;
	SOCKADDR_IN server;
	HOSTENT* host;
	sntppacket sendp,recvp;
	int fromsize;
	int gotsize;
	char filename[1025];
	int i;
	HANDLE fp;
	DWORD writtensize;
	double msec,kizyun;
	SYSTEMTIME st;
	unsigned int ms;
	unsigned long long starttime;
	unsigned long long gettime;
	unsigned long long sendtime;
	unsigned long long endtime;
	unsigned long zikan;
	time_t ttime;
	struct tm* ptime;
	printf("サーバー?");
	scanf("%s",servername);
	if(WSAStartup(MAKEWORD(1,1),&wsa)) {
		printf("開始エラー\n");
		return 1;
	}
	sock=socket(AF_INET,SOCK_DGRAM,0);
	if(sock==INVALID_SOCKET) {
		printf("ソケット作成エラー");
		WSACleanup();
		return 1;
	}
	server.sin_family=AF_INET;
	server.sin_port=htons(123);
	server.sin_addr.s_addr=inet_addr(servername);
	if(server.sin_addr.s_addr==0xFFFFFFFF) {
		host=gethostbyname(servername);
		if(host==0) {
			if(WSAGetLastError()==WSAHOST_NOT_FOUND)
				printf("サーバーが見つかりません\n");
			else printf("サーバー検索エラー\n");
			closesocket(sock);
			WSACleanup();
			return 1;
		}
		server.sin_addr.s_addr=*((unsigned long*)host->h_addr);
	}
	RtlFillMemory(&sendp,sizeof(sendp),0);
	sendp.seigyo=0x0B;
	sendp.sentstamp.hidword=htonl((unsigned long)time(NULL)+2208988800UL);
	GetLocalTime(&st);
	msec=st.wMilliseconds;
	kizyun=500;
	ms=0;
	for(i=31;i>=0;i--) {
		if(msec>=kizyun) {
			ms|=1<<i;
			msec-=kizyun;
		}
		kizyun/=2;
	}
	sendp.sentstamp.lodword=htonl((unsigned long)ms);
	if(sendto(sock,(const char*)&sendp,sizeof(sendp),0,
			(SOCKADDR*)&server,sizeof(server))==SOCKET_ERROR) {
		printf("送信エラー\n");
		closesocket(sock);
		WSACleanup();
		return 1;
	}
	fromsize=sizeof(server);
	gotsize=recvfrom(sock,(char*)&recvp,sizeof(recvp),0,
		(SOCKADDR*)&server,&fromsize);
	if(gotsize==SOCKET_ERROR) {
		printf("受信エラー\n");
		closesocket(sock);
		WSACleanup();
		return 1;
	}
	starttime=(unsigned long long)ntohl(recvp.kaitstamp.hidword)<<32 |
	          (unsigned long long)ntohl(recvp.kaitstamp.lodword);
	gettime=(unsigned long long)ntohl(recvp.rectstamp.hidword)<<32 |
	          (unsigned long long)ntohl(recvp.rectstamp.lodword);
	sendtime=(unsigned long long)ntohl(recvp.sentstamp.hidword)<<32 |
	          (unsigned long long)ntohl(recvp.sentstamp.lodword);
	endtime=((unsigned long long)time(NULL)+2208988800ULL)<<32;
	GetLocalTime(&st);
	msec=st.wMilliseconds;
	kizyun=500;
	ms=0;
	for(i=31;i>=0;i--) {
		if(msec>=kizyun) {
			ms|=1<<i;
			msec-=kizyun;
		}
		kizyun/=2;
	}
	endtime|=(unsigned long long)ms;
	sendtime+=((endtime-starttime)-(sendtime-gettime))/2;
	ttime=(time_t)(sendtime>>32)-2208988800UL;
	zikan=(unsigned int)(sendtime & 0xffffffff);
	msec=0;
	kizyun=500;
	for(i=31;i>=0;i--) {
		if(zikan & (1<<i))msec+=kizyun;
		kizyun/=2;
	}
	ms=(unsigned int)msec;
	for(i=0;;i++) {
		wsprintf(filename,"gotdata\\gotdata%04d.ntp",i);
		fp=CreateFile(filename,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);
		if(fp!=INVALID_HANDLE_VALUE)break;
	}
	WriteFile(fp,&recvp,gotsize,&writtensize,NULL);
	CloseHandle(fp);
	closesocket(sock);
	WSACleanup();
	printf("正常終了\n");
	ptime=localtime(&ttime);
	printf("時刻:%d年%d月%d日%d時%d分%d秒%d\n",
		st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
	printf("結果:%d年%d月%d日%d時%d分%d秒%d\n",
		ptime->tm_year+1900,ptime->tm_mon+1,ptime->tm_mday,
		ptime->tm_hour,ptime->tm_min,ptime->tm_sec,ms);
	return 0;
}
参考
NTPサーバ一覧
http://www.venus.dti.ne.jp/~yoshi-o/NTP/NTP-Table.html

でも、ほぼ自分ばっかり投稿しているなあ...
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6067
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: SNTPで時刻取得

#2

投稿記事 by みけCAT » 7年前

localtime関数がNULLを返す可能性に対処しました。

コード:

#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <time.h>

/*環境依存*/
#include <limits.h>
#if UCHAR_MAX!=0xff || UINT_MAX!=0xffffffff
#error Variable size can't accepted.
#endif
#if ULONG_MAX!=0xffffffff || ULLONG_MAX!=0xffffffffffffffff
#error Variable size can't accepted.
#endif

typedef struct {
	unsigned int hidword;
	unsigned int lodword;
} rybits;

typedef struct {
	unsigned char seigyo;
	unsigned char kaisou;/*階層*/
	unsigned char bkankaku;/*ボーリング間隔*/
	unsigned char seido;/*精度*/
	unsigned int rdelay;/*ルート遅延*/
	unsigned int rkaku;/*ルート拡散*/
	unsigned int ssikibetu;/*参照識別子*/
	rybits santstamp;/*参照タイムスタンプ*/
	rybits kaitstamp;/*開始タイムスタンプ*/
	rybits rectstamp;/*受信タイムスタンプ*/
	rybits sentstamp;/*送信タイムスタンプ*/
	unsigned int key;/*鍵識別子*/
	rybits md[2];/*メッセージダイジェスト*/
} sntppacket;

int main(void) {
	char servername[1024];
	WSADATA wsa;
	SOCKET sock;
	SOCKADDR_IN server;
	HOSTENT* host;
	sntppacket sendp,recvp;
	int fromsize;
	int gotsize;
	char filename[1025];
	int i;
	HANDLE fp;
	DWORD writtensize;
	double msec,kizyun;
	SYSTEMTIME st;
	unsigned int ms;
	unsigned long long starttime;
	unsigned long long gettime;
	unsigned long long sendtime;
	unsigned long long endtime;
	unsigned long zikan;
	time_t ttime;
	struct tm* ptime;
	printf("サーバー?");
	scanf("%s",servername);
	if(WSAStartup(MAKEWORD(1,1),&wsa)) {
		printf("開始エラー\n");
		return 1;
	}
	sock=socket(AF_INET,SOCK_DGRAM,0);
	if(sock==INVALID_SOCKET) {
		printf("ソケット作成エラー");
		WSACleanup();
		return 1;
	}
	server.sin_family=AF_INET;
	server.sin_port=htons(123);
	server.sin_addr.s_addr=inet_addr(servername);
	if(server.sin_addr.s_addr==0xFFFFFFFF) {
		host=gethostbyname(servername);
		if(host==0) {
			if(WSAGetLastError()==WSAHOST_NOT_FOUND)
				printf("サーバーが見つかりません\n");
			else printf("サーバー検索エラー\n");
			closesocket(sock);
			WSACleanup();
			return 1;
		}
		server.sin_addr.s_addr=*((unsigned long*)host->h_addr);
	}
	RtlFillMemory(&sendp,sizeof(sendp),0);
	sendp.seigyo=0x0B;
	sendp.sentstamp.hidword=htonl((unsigned long)time(NULL)+2208988800UL);
	GetLocalTime(&st);
	msec=st.wMilliseconds;
	kizyun=500;
	ms=0;
	for(i=31;i>=0;i--) {
		if(msec>=kizyun) {
			ms|=1<<i;
			msec-=kizyun;
		}
		kizyun/=2;
	}
	sendp.sentstamp.lodword=htonl((unsigned long)ms);
	if(sendto(sock,(const char*)&sendp,sizeof(sendp),0,
			(SOCKADDR*)&server,sizeof(server))==SOCKET_ERROR) {
		printf("送信エラー\n");
		closesocket(sock);
		WSACleanup();
		return 1;
	}
	fromsize=sizeof(server);
	gotsize=recvfrom(sock,(char*)&recvp,sizeof(recvp),0,
		(SOCKADDR*)&server,&fromsize);
	if(gotsize==SOCKET_ERROR) {
		printf("受信エラー\n");
		closesocket(sock);
		WSACleanup();
		return 1;
	}
	starttime=(unsigned long long)ntohl(recvp.kaitstamp.hidword)<<32 |
	          (unsigned long long)ntohl(recvp.kaitstamp.lodword);
	gettime=(unsigned long long)ntohl(recvp.rectstamp.hidword)<<32 |
	          (unsigned long long)ntohl(recvp.rectstamp.lodword);
	sendtime=(unsigned long long)ntohl(recvp.sentstamp.hidword)<<32 |
	          (unsigned long long)ntohl(recvp.sentstamp.lodword);
	endtime=((unsigned long long)time(NULL)+2208988800ULL)<<32;
	GetLocalTime(&st);
	msec=st.wMilliseconds;
	kizyun=500;
	ms=0;
	for(i=31;i>=0;i--) {
		if(msec>=kizyun) {
			ms|=1<<i;
			msec-=kizyun;
		}
		kizyun/=2;
	}
	endtime|=(unsigned long long)ms;
	sendtime+=((endtime-starttime)-(sendtime-gettime))/2;
	ttime=(time_t)((sendtime>>32)-2208988800ULL);
	zikan=(unsigned int)(sendtime & 0xffffffff);
	msec=0;
	kizyun=500;
	for(i=31;i>=0;i--) {
		if(zikan & (1<<i))msec+=kizyun;
		kizyun/=2;
	}
	ms=(unsigned int)msec;
	for(i=0;;i++) {
		wsprintf(filename,"gotdata\\gotdata%04d.ntp",i);
		fp=CreateFile(filename,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);
		if(fp!=INVALID_HANDLE_VALUE)break;
	}
	WriteFile(fp,&recvp,gotsize,&writtensize,NULL);
	CloseHandle(fp);
	closesocket(sock);
	WSACleanup();
	printf("正常終了\n");
	ptime=localtime(&ttime);
	printf("時刻:%d年%d月%d日%d時%d分%d秒%d\n",
		st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
	if(ptime!=NULL)
	printf("結果:%d年%d月%d日%d時%d分%d秒%d\n",
		ptime->tm_year+1900,ptime->tm_mon+1,ptime->tm_mday,
		ptime->tm_hour,ptime->tm_min,ptime->tm_sec,ms);
	else printf("結果:1970年1月1日0:00から%u秒%d\n",(unsigned int)ttime,ms);
	return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

返信

“サンプルを共有するコミュニティ” へ戻る