您的位置:首页 > 理论基础 > 计算机网络

使用NTP协议获取网络时间代码

2014-04-21 20:59 489 查看
协议包:



主要字段的解释如下:

l LI(Leap Indicator):长度为2比特,值为“11”时表示告警状态,时钟未被同步。为其他值时NTP本身不做处理。

l VN(Version Number):长度为3比特,表示NTP的版本号,目前的最新版本为3。

l Mode:长度为3比特,表示NTP的工作模式。不同的值所表示的含义分别是:0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7预留给内部使用。

l Stratum:系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态,不能作为参考时钟。

l Poll:轮询时间,即两个连续NTP报文之间的时间间隔。

l Precision:系统时钟的精度。

l Root Delay:本地到主参考时钟源的往返时间。

l Root Dispersion:系统时钟相对于主参考时钟的最大误差。

l Reference Identifier:参考时钟源的标识。

l Reference Timestamp:系统时钟最后一次被设定或更新的时间。

l Originate Timestamp:NTP请求报文离开发送端时发送端的本地时间。

l Receive Timestamp:NTP请求报文到达接收端时接收端的本地时间。

l Transmit Timestamp:应答报文离开应答者时应答者的本地时间。

l Authenticator:验证信息。

class NetworkUInt64
{
public:
operator UINT64()
{
return htonll(nData);
}

const NetworkUInt64& operator = (UINT64 nValue)
{
nData = htonll(nValue);
return *this;
}
protected:
UINT64	nData;
};

const static ULONGLONG n1970_1900_Seconds = 2208988800;

__declspec(align(1)) struct NTPData
{
unsigned int Mode : 3;
unsigned int VersionNumber : 3;
unsigned int LeapIndicator : 2;
unsigned int Stratum : 8;
unsigned int Poll : 8;
unsigned int Precision : 8;
unsigned int RootDelay : 32;
unsigned int RootDispersion : 32;
unsigned int ReferenceIdentifier : 32;
NetworkUInt64 ReferenceTimestamp;
NetworkUInt64 OriginateTimestamp;
NetworkUInt64 ReceiveTimestamp;
NetworkUInt64 TransmitTimestamp;
};

int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL, ".ACP");

WSADATA wsaData;
SOCKET SendSocket;
sockaddr_in RecvAddr;
int Port = 123;

//---------------------------------------------
// 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);
HOSTENT* pHostent = gethostbyname("time.nist.gov");
if (pHostent != NULL)
{
RecvAddr.sin_addr.s_addr = *(u_long *)pHostent->h_addr_list[0];;
}

//---------------------------------------------
// Send a datagram to the receiver
printf("Sending a datagram to the receiver...\n");

// Set version number to 3 and Mode to 3 (client)
NTPData data = { 0 };
data.VersionNumber = 3;
data.Mode = 3;
int tv_out = 10000;
setsockopt(SendSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_out, sizeof(tv_out));

__time64_t startTime = _time64(NULL);
sendto(SendSocket, (char*)&data, sizeof(data), 0, (SOCKADDR *)&RecvAddr, sizeof(RecvAddr));

sockaddr fromAddr = { 0 };
int nRead = sizeof(fromAddr);
if (SOCKET_ERROR != recvfrom(SendSocket, (char*)&data, sizeof(data), 0, &fromAddr, &nRead))
{
__time64_t curTime = _time64(NULL);
__time64_t serverReceiveTime = (UINT64(data.ReceiveTimestamp) >> 32) - n1970_1900_Seconds;
__time64_t serverTransmitTime = (UINT64(data.TransmitTimestamp) >> 32) - n1970_1900_Seconds;
}
else
{
cout << "WSAGetLastError:" << WSAGetLastError() << endl;
}

//---------------------------------------------
// When the application is finished sending, close the socket.
printf("Finished sending. Closing socket.\n");
closesocket(SendSocket);

//---------------------------------------------
// Clean up and quit.
printf("Exiting.\n");
WSACleanup();

system("pause");
return 0;
}


字段解释来自 http://blog.163.com/yzc_5001/blog/static/2061963420121283050787/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: