#include<sys/socket.h>#include<sys/wait.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<string.h>#include<sys/un.h>#include<sys/time.h>#include<sys/ioctl.h>#include<unistd.h>#include<netinet/in.h>#include<string.h>#include<netdb.h>#defineNTP_PORT123/*NTP专用端口号字符串*/#defineTIME_PORT37/*TIME/UDP端口号*/#defineNTP_SERVER_IP"61.135.250.78"/*国家授时中心IP*/#defineNTP_PORT_STR"123"/*NTP专用端口号字符串*/#defineNTPV1"NTP/V1"/*协议及其版本号*/#defineNTPV2"NTP/V2"#defineNTPV3"NTP/V3"#defineNTPV4"NTP/V4"#defineTIME"TIME/UDP"#defineNTP_PCK_LEN48#defineLI0#defineVN3#defineMODE3#defineSTRATUM0#definePOLL4#definePREC-6#defineJAN_19700x83aa7e80/*1900年~1970年之间的时间秒数*/#defineNTPFRAC(x)(4294*(x)+((1981*(x))>>11))#defineUSEC(x)(((x)>>12)-759*((((x)>>10)+32768)>>16))typedefstruct_ntp_time{unsignedintcoarse;unsignedintfine;}ntp_time;structntp_packet{unsignedcharleap_ver_mode;unsignedcharstartum;charpoll;charprecision;introot_delay;introot_dispersion;intreference_identifier;ntp_timereference_timestamp;ntp_timeoriginage_timestamp;ntp_timereceive_timestamp;ntp_timetransmit_timestamp;};charprotocol[32];/*构建NTP协议包*/intconstruct_packet(char*packet){charversion=1;longtmp_wrd;intport;time_ttimer;strcpy(protocol,NTPV3);/*判断协议版本*/if(!strcmp(protocol,NTPV1)||!strcmp(protocol,NTPV2)||!strcmp(protocol,NTPV3)||!strcmp(protocol,NTPV4)){memset(packet,0,NTP_PCK_LEN);port=NTP_PORT;/*设置16字节的包头*/version=protocol[6]-0x30;tmp_wrd=htonl((LI<<30)|(version<<27)|(MODE<<24)|(STRATUM<<16)|(POLL<<8)|(PREC&0xff));memcpy(packet,&tmp_wrd,sizeof(tmp_wrd));/*设置RootDelay、RootDispersion和ReferenceIndentifier*/tmp_wrd=htonl(1<<16);memcpy(&packet[4],&tmp_wrd,sizeof(tmp_wrd));memcpy(&packet[8],&tmp_wrd,sizeof(tmp_wrd));/*设置Timestamp部分*/time(&timer);/*设置TransmitTimestampcoarse*/tmp_wrd=htonl(JAN_1970+(long)timer);memcpy(&packet[40],&tmp_wrd,sizeof(tmp_wrd));/*设置TransmitTimestampfine*/tmp_wrd=htonl((long)NTPFRAC(timer));memcpy(&packet[44],&tmp_wrd,sizeof(tmp_wrd));returnNTP_PCK_LEN;}elseif(!strcmp(protocol,TIME))/*"TIME/UDP"*/{port=TIME_PORT;memset(packet,0,4);return4;}return0;}/*获取NTP时间*/intget_ntp_time(intsk,structaddrinfo*addr,structntp_packet*ret_time){fd_setpending_data;structtimevalblock_time;chardata[NTP_PCK_LEN*8];intpacket_len,data_len=addr->ai_addrlen,count=0,result,i,re;if(!(packet_len=construct_packet(data))){return0;}/*客户端给服务器端发送NTP协议数据包*/if((result=sendto(sk,data,packet_len,0,addr->ai_addr,data_len))<0){perror("sendto");return0;}/*调用select()函数,并设定超时时间为1s*/FD_ZERO(&pending_data);FD_SET(sk,&pending_data);block_time.tv_sec=10;block_time.tv_usec=0;if(select(sk+1,&pending_data,NULL,NULL,&block_time)>0){/*接收服务器端的信息*/if((count=recvfrom(sk,data,NTP_PCK_LEN*8,0,addr->ai_addr,&data_len))<0){perror("recvfrom");return0;}if(protocol==TIME){memcpy(&ret_time->transmit_timestamp,data,4);return1;}elseif(count<NTP_PCK_LEN){return0;}/*设置接收NTP包的数据结构*/ret_time->leap_ver_mode=ntohl(data[0]);ret_time->startum=ntohl(data[1]);ret_time->poll=ntohl(data[2]);ret_time->precision=ntohl(data[3]);ret_time->root_delay=ntohl(*(int*)&(data[4]));ret_time->root_dispersion=ntohl(*(int*)&(data[8]));ret_time->reference_identifier=ntohl(*(int*)&(data[12]));ret_time->reference_timestamp.coarse=ntohl(*(int*)&(data[16]));ret_time->reference_timestamp.fine=ntohl(*(int*)&(data[20]));ret_time->originage_timestamp.coarse=ntohl(*(int*)&(data[24]));ret_time->originage_timestamp.fine=ntohl(*(int*)&(data[28]));ret_time->receive_timestamp.coarse=ntohl(*(int*)&(data[32]));ret_time->receive_timestamp.fine=ntohl(*(int*)&(data[36]));ret_time->transmit_timestamp.coarse=ntohl(*(int*)&(data[40]));ret_time->transmit_timestamp.fine=ntohl(*(int*)&(data[44]));return1;}/*endofifselect*/return0;}/*修改本地时间*/intset_local_time(structntp_packet*pnew_time_packet){structtimevaltv;tv.tv_sec=pnew_time_packet->transmit_timestamp.coarse-JAN_1970;tv.tv_usec=USEC(pnew_time_packet->transmit_timestamp.fine);returnsettimeofday(&tv,NULL);}intmain(){intsockfd,rc;structaddrinfohints,*res=NULL;structntp_packetnew_time_packet;memset(&hints,0,sizeof(hints));hints.ai_family=AF_UNSPEC;hints.ai_socktype=SOCK_DGRAM;hints.ai_protocol=IPPROTO_UDP;/*调用getaddrinfo()函数,获取地址信息*/rc=getaddrinfo(NTP_SERVER_IP,NTP_PORT_STR,&hints,&res);if(rc!=0){perror("getaddrinfo");return1;}/*创建套接字*/sockfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol);if(sockfd<0){perror("socket");return1;}/*调用取得NTP时间的函数*/if(get_ntp_time(sockfd,res,&new_time_packet)){/*调整本地时间*/if(!set_local_time(&new_time_packet)){printf("NTPclientsuccess!\n");}}close(sockfd);return0;}