⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ntpclient.c

📁 简单的时间服务器的客户端程序
💻 C
字号:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/timeb.h>
#include <time.h>
#include <winsock.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4244)


#define NTP_SERVER    "192.168.111.115"
#define NTP_PORT      123

const char Days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

void stdcalllocaltimes( time_t time, long timezone, struct tm *tm_time);

#define JAN_1970      0x83aa7e80      /* 2208988800 1970 - 1900 in seconds */

/* How to multiply by 4294.967296 quickly (and not quite exactly)
* without using floating point or greater than 32-bit integers.
* If you want to fix the last 12 microseconds of error, add in
* (2911*(x))>>28)
*/
#define NTPFRAC(x) (4294 * (x) + ((1981 * (x))>>11))

/* The reverse of the above, needed if we want to set our microsecond
 * clock (via settimeofday) based on the incoming time in NTP format.
 * Basically exact.
 */
#define USEC(x) (((x) >> 12) - 759 * ((((x) >> 10) + 32768) >> 16))

void stdcalllocaltimes( time_t time,long timezone,struct tm *tm_time)
 { 
	 unsigned  __int32 n32_Pass4year; 
	 __int32 n32_hpery;

	 time = time + timezone;
	 if(time < 0){
		 time = 0;    
	 }														//取秒时间
	 tm_time->tm_sec=(int)(time % 60);    
	 time /= 60;											//取分钟时间
	 tm_time->tm_min=(int)(time % 60);    
	 time /= 60;											//取过去多少个四年,每四年有 1461*24 小时
	 n32_Pass4year=((unsigned int)time / (1461L * 24L));	//计算年份
	 tm_time->tm_year=(n32_Pass4year << 2)+70;				//四年中剩下的小时数
	 time %= 1461L * 24L;									//校正闰年影响的年份,计算一年中剩下的小时数
	 for (;;) {												//一年的小时数        
		 n32_hpery = 365 * 24;								//判断闰年
		 if ((tm_time->tm_year & 3) == 0){					//是闰年,一年则多24小时,即一天
			 n32_hpery += 24;
		 }
		 if (time < n32_hpery){
			 break;
		 }
		 tm_time->tm_year++;
		 time -= n32_hpery;
		 }													//小时数
	 tm_time->tm_hour=(int)(time % 24);						//一年中剩下的天数
	 time /= 24;											//假定为闰年
	 time++;												//校正润年的误差,计算月份,日期
	 if ((tm_time->tm_year & 3) == 0) {
		 if (time > 60){			
			 time--;
		 }
		 else{
			 if (time == 60){
				 tm_time->tm_mon = 1;
				 tm_time->tm_mday = 29;
				 return ;
				 }
		 }
	 }														//计算月日
	 for (tm_time->tm_mon = 0; Days[tm_time->tm_mon] < time;tm_time->tm_mon++) {
		 time -= Days[tm_time->tm_mon];
	 }
	 tm_time->tm_mday = (int)(time);
	 return;
 }


struct ntptime 
{
	unsigned int coarse;
	unsigned int fine;
};


void send_packet(int fd)
{
	unsigned int data[12];
	/*struct timeval now;*/
	struct _timeb now;
	int ret;
#define LI 0
#define VN 3
#define MODE 3
#define STRATUM 0
#define POLL 4 
#define PREC -6

	if (sizeof(data) != 48) 
	{
		fprintf(stderr,"size error\n");
		return;
	}

	memset((char*)data, 0, sizeof(data));
	data[0] = htonl((LI << 30) | (VN << 27) | (MODE << 24) 
	              | (STRATUM << 16) | (POLL << 8) | (PREC & 0xff));
	data[1] = htonl(1<<16);  /* Root Delay (seconds) */
	data[2] = htonl(1<<16);  /* Root Dispersion (seconds) */
	_ftime(&now);
	/*gettimeofday(&now, NULL);*/
	data[10] = htonl(now.time + JAN_1970); /* Transmit Timestamp coarse */
	data[11] = htonl(NTPFRAC(now.millitm));  /* Transmit Timestamp fine   */
	ret = send(fd, (char*)data, 48, 0);
	printf("Send packet to ntp server, ret: %d\n", ret);
}

void get_packet_timestamp(int usd, struct ntptime *udp_arrival_ntp)
{
	/*struct timeval udp_arrival;*/
	struct _timeb udp_arrival;

	_ftime(&udp_arrival);
	/*gettimeofday(&udp_arrival, NULL);*/
	udp_arrival_ntp->coarse = udp_arrival.time + JAN_1970;
	udp_arrival_ntp->fine   = NTPFRAC(udp_arrival.millitm);
}

void rfc1305print(unsigned int *data, struct ntptime *arrival, struct timeval* tv)
{
/* straight out of RFC-1305 Appendix A */
	int li, vn, mode, stratum, poll, prec;
	int delay, disp, refid;
	struct ntptime reftime, orgtime, rectime, xmttime;
	struct tm timevalue;
	struct tm *ltm = &timevalue;
	long timezone = 28800;


#define Data(i) ntohl(((unsigned int *)data)[i])
	li      = Data(0) >> 30 & 0x03;
	vn      = Data(0) >> 27 & 0x07;
	mode    = Data(0) >> 24 & 0x07;
	stratum = Data(0) >> 16 & 0xff;
	poll    = Data(0) >>  8 & 0xff;
	prec    = Data(0)       & 0xff;
	if (prec & 0x80) prec|=0xffffff00;
	delay   = Data(1);
	disp    = Data(2);
	refid   = Data(3);
	reftime.coarse = Data(4);
	reftime.fine   = Data(5);
	orgtime.coarse = Data(6);
	orgtime.fine   = Data(7);
	rectime.coarse = Data(8);
	rectime.fine   = Data(9);
	xmttime.coarse = Data(10);
	xmttime.fine   = Data(11);
#undef Data

	tv->tv_sec = xmttime.coarse - JAN_1970;
	tv->tv_usec = USEC(xmttime.fine);
	stdcalllocaltimes(tv->tv_sec, timezone, ltm);
	printf("Get ntp server time: %.4d_%.2d_%.2d %.2d:%.2d:%.2d\n", 
			ltm->tm_year + 1900, 
			ltm->tm_mon + 1, 
			ltm->tm_mday, 
			ltm->tm_hour, 
			ltm->tm_min, 
			ltm->tm_sec);
}

void set_local_time(struct timeval tv)
{
	SYSTEMTIME time;
	struct tm timevalue;
	struct tm *ltm = &timevalue;
	long timezone = 28800;
	
	stdcalllocaltimes(tv.tv_sec, timezone, ltm);
	time.wYear = ltm->tm_year + 1900;
	time.wMonth = ltm->tm_mon + 1;
	time.wDay = ltm->tm_mday;
	time.wHour = ltm->tm_hour;
	time.wMinute = ltm->tm_min;
	time.wSecond = ltm->tm_sec;
	time.wMilliseconds = 0;
	if (0 == SetLocalTime(&time))
	{
		perror("SetLocalTime");
		return;
	}

	printf("set local time to ntp server's time.\n");
}

int main(void)
{
	int sock;
	struct sockaddr_in addr_src;
	struct sockaddr_in addr_dst;
	int addr_len = sizeof(struct sockaddr_in);
	
	/*WSAStartup*/
	WSADATA wsadata;
	WSAStartup(MAKEWORD(2,2), &wsadata);

	/* create socket. */
	sock = socket(PF_INET, SOCK_DGRAM, 0);
	if (-1 == sock)
	{
		perror("create socket");
		exit(1);
	}

	/* bind local address. */
	memset(&addr_src, 0, addr_len);
	addr_src.sin_family = AF_INET;
	addr_src.sin_addr.s_addr = htonl(INADDR_ANY);
	addr_src.sin_port = htons(0);
	if (-1 == bind(sock, (struct sockaddr*)&addr_src, addr_len))
	{
		perror("bind socket");
		exit(1);
	}

	/* connect to ntp server. */
	memset(&addr_dst, 0, addr_len);
	addr_dst.sin_family = AF_INET;
	{
		struct hostent* host = gethostbyname(NTP_SERVER);
		if (NULL == host)
		{
			perror("gethostbyname");
			exit(1);
		}
		if (4 != host->h_length)
		{
			fprintf(stderr, "host->h_length is not 4!\n");
			exit(1);
		}
		memcpy(&(addr_dst.sin_addr.s_addr), host->h_addr_list[0], 4);
	}
	addr_dst.sin_port = htons(NTP_PORT);
	printf("Connecting to ntp server: %s ip: %s port: %d ...\n", 
	       NTP_SERVER, inet_ntoa(addr_dst.sin_addr), NTP_PORT);
	if (-1 == connect(sock, (struct sockaddr*)&addr_dst, addr_len))
	{
		perror("connect ntp server");
		exit(1);
	}

	while (1)
	{
		fd_set fds_read;
		struct timeval timeout;
		int ret;

		unsigned int buf[12];
		int len;
		
		struct sockaddr server = {0};
		int svr_len = sizeof(struct sockaddr);
		struct ntptime arrival_ntp;
		struct timeval newtime;

		FD_ZERO(&fds_read);
		FD_SET(sock, &fds_read);

		timeout.tv_sec = 6;
		timeout.tv_usec = 0;
		ret = select(sock + 1, &fds_read, NULL, NULL, &timeout);
		if (-1 == ret)
		{
			perror("select");
			exit(1);
		}
		if (0 == ret || !FD_ISSET(sock, &fds_read))
		{
			/* send ntp protocol packet. */
			send_packet(sock);
			continue;
		}

		/* recv ntp server's response. */
		len = recvfrom(sock, (char*)buf, sizeof(buf), 0, (struct sockaddr*)&server, &svr_len);
		if (-1 == len)
		{
			perror("recvfrom");
			exit(1);
		}
		if (0 == len)
		{
			continue;
		}

		/* get local timestamp. */
		get_packet_timestamp(sock, &arrival_ntp);
		/* get server's time and print it. */
		rfc1305print(buf, &arrival_ntp, &newtime);
		/* set local time to the server's time, if you're a root user. */
		set_local_time(newtime);
	}

	closesocket(sock);
	WSACleanup();
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -