NTP测试
向NTP服务器发送特定报文,即可收到回复,不考虑传输延迟的话,解析时间很简单。
测试可用的NTP服务器:202.120.2.101 端口:123
例如发送的报文:(48字节)1b 00 04 fa 00 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
收到的回复是:(48字节)
1C 03 04 E9 00 00 0A 07 00 00 0E 04 CA 76 01 82 D9 FD 82 DE 62 51 F1 C6 00 00 00 00 00 00 00 00 D9 FD 84 95 94 F8 59 7C D9 FD 84 95 94 FB 59 E1
然后就可以根据协议解析时间了。
上图用网络调试助手发送和接收
参考代码:
#include <stdio.h> #include "winsock2.h" #include <time.h> #include <conio.h> #pragma comment (lib,"ws2_32.lib")//连入库文件 //******************************// // 定义一个结构,就是NTP包的结构// //******************************// /*NTP 消息的格式被显示如下。 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |LI | VN |Mode | Stratum | Poll | Precision | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 根延迟 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 根差量 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 参考标识符 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | 参考时间戳(64) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | 原始时间戳(64) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | 接受时间戳 (64) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | 传送时间戳(64) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | | | 认证符(可选项) (96) | | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ typedef struct ntp { char Flag; char PeerClockStratum; char PeerPollingInterval; char PeerClockPrecision; char RootDelay[4]; char ClockDispersion[4]; char ReferenceClock[4]; char ReferenceClockUpdateTime[8]; char OriginateTimeStamp[8]; char ReceiveTimeStamp[8]; char TransmitTimeStamp[8]; } tagNTP; //*********************************************************// // 定义一个函数,设置操作系统时间的函数 // // SetNewTime - sets system time // // Return value - TRUE if successful, FALSE otherwise // // hour - new hour (0-23) // // minutes - new minutes (0-59) // // Author:白色猎人 [Unicorn QQ:233536605] // //*********************************************************// BOOL SetNewTime(WORD year,WORD month,WORD day,WORD hour, WORD minutes,WORD second) { SYSTEMTIME st; GetSystemTime(&st); // gets current time st.wYear=year+1900; // adjusts year st.wMonth=month+1; // adjusts month st.wDay =day; // adjusts day st.wHour =hour; // adjusts hours st.wMinute =minutes; // and minutes st.wSecond =second; // and second if (!SetLocalTime(&st)) return FALSE;// sets system time return TRUE; } typedef unsigned char uchar; void printn(uchar *buf,uchar len) { while(len--) { printf("0x%02x ",*buf++); } } void main() { SYSTEMTIME st; WSADATA wsaData; SOCKET SendSocket; sockaddr_in RecvAddr; //Receive Data sockaddr_in SenderAddr; int SenderAddrSize = sizeof(SenderAddr); ntp SendBuf; int Port = 123; //NTP端口为:123 //以下变量的赋值均来源于NTP数据包,你可以用Ethereal抓包 SendBuf.Flag =0x1b;//0001 1011 SendBuf.PeerClockStratum =0x00; SendBuf.PeerPollingInterval =0x00; SendBuf.PeerClockPrecision =0x00; memset(SendBuf.RootDelay ,0,4); memset(SendBuf.ClockDispersion,0,4); memset(SendBuf.ReferenceClock,0,4); memset(SendBuf.ReferenceClockUpdateTime,0,8); memset(SendBuf.OriginateTimeStamp,0,8); memset(SendBuf.ReceiveTimeStamp,0,8); //memcpy(&SendBuf.TransmitTimeStamp[0],"0xc7",1); //memcpy(&SendBuf.TransmitTimeStamp[1],"0x50",1); //memcpy(&SendBuf.TransmitTimeStamp[2],"0xe7",1); //memcpy(&SendBuf.TransmitTimeStamp[3],"0xa0",1); //SendBuf.TransmitTimeStamp[0]=0xc7; //SendBuf.TransmitTimeStamp[1]=0x50; //SendBuf.TransmitTimeStamp[2]=0xe7; //SendBuf.TransmitTimeStamp[3]=0xa0; SendBuf.TransmitTimeStamp[0]=0; SendBuf.TransmitTimeStamp[1]=0; SendBuf.TransmitTimeStamp[2]=0; SendBuf.TransmitTimeStamp[3]=0; SendBuf.TransmitTimeStamp[4]=0x00; SendBuf.TransmitTimeStamp[5]=0x00; SendBuf.TransmitTimeStamp[6]=0x00; SendBuf.TransmitTimeStamp[7]=0x00; char *ptr; ptr=(char *)&SendBuf; int i; for(i=0;i<sizeof(SendBuf);i++) { printf("%x\r\n",*(ptr+i)); } *(ptr+0)= (0 <<6) | (3 <<3) | (3); *(ptr+1)= 0; *(ptr+2)= 4; *(ptr+3)= -6 & 0xff; *(ptr+5)= 1; *(ptr+9)= 1; int BufLen = 48; //包的长度为48字节 tm *newtime; time_t long_time; //--------------------------------------------- // Initialize Winsock WSAStartup(MAKEWORD(2,2), &wsaData); //--------------------------------------------- // Create a socket for sending data SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Set up the RecvAddr structure with the IP address of the receiver (in this example case "123.456.789.1") and the specified port number. RecvAddr.sin_family = AF_INET; RecvAddr.sin_port = htons(Port); //RecvAddr.sin_addr.s_addr = inet_addr("61.129.42.44"); //RecvAddr.sin_addr.s_addr = inet_addr("time.windows.com"); //RecvAddr.sin_addr.s_addr = inet_addr("192.168.2.101"); RecvAddr.sin_addr.s_addr = inet_addr("202.120.2.101"); //RecvAddr.sin_addr.s_addr = inet_addr("cn.pool.ntp.org"); //RecvAddr.sin_addr.s_addr = inet_addr("133.100.11.8");//"133.100.11.8");//"133.100.9.2"); 两个一级代理好用 //所有的服务器见http://support.microsoft.com/?scid=kb;zh-cn;262680&spid=1131&sid=795//地址为210.72.145.44 (中国国家授时中心) // Send a datagram to the receiver printf("Sending a datagram to the receiver...\n"); sendto(SendSocket, (char *)&SendBuf, BufLen, 0, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr)); printf("%d\r\n",sizeof(RecvAddr)); printn((uchar*)&SendBuf,48); //printf("Finished sending.\n"); /*开始接收发过来的数据*/ printf("Receiving datagrams...\n"); recvfrom(SendSocket,(char *)&SendBuf, BufLen, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize); //printf("Finished receiving.Closing socket.\n"); closesocket(SendSocket); //********************************************* memcpy(&long_time,SendBuf.ReceiveTimeStamp,4); //从收到的包里面取出前32位放入变量long_time中 printn((uchar*)&SendBuf,48); //printf("%d\n",long_time); long_time = ntohl(long_time)-2208988800; //把低位的字节和高位字节互换 newtime = localtime(&long_time); /* Convert to local time. */ SetNewTime(newtime->tm_year,newtime->tm_mon,newtime->tm_mday,newtime->tm_hour,newtime->tm_min,newtime->tm_sec); GetSystemTime(&st); // gets current time st.wYear=newtime->tm_year+1900; // adjusts year st.wMonth=newtime->tm_mon+1; // adjusts month st.wDay =newtime->tm_mday; // adjusts day st.wHour =newtime->tm_hour; // adjusts hours st.wMinute =newtime->tm_min; // and minutes st.wSecond =newtime->tm_sec; // and second SetLocalTime(&st);// sets system time //--------------------------------------------- // Clean up and quit. //--------------------------------------------- //printf("OK,Exiting.\n"); printf("%d年%d月%d日%d时%d分%d秒",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); WSACleanup(); getch(); return; } /* 0x1b 0x00 0x04 0xfa 0x00 0x01 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 1b 00 04 fa 00 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */