📄 ntpclient.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 + -