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
*/
浙公网安备 33010602011771号