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

协议包:

NTP技术 - yu - sms

主要字段的解释如下:

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/


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是使用C++获取NTP网络时间的示例代码: ```c++ #include <iostream> #include <WinSock2.h> #include <windows.h> #include <time.h> #pragma comment(lib, "Ws2_32.lib") #define NTP_TIMESTAMP_DELTA 2208988800ull int main() { // 初始化Winsock WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { std::cout << "WSAStartup failed with error: " << iResult << std::endl; return 1; } // 创建UDP套接字 SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) { std::cout << "socket failed with error: " << WSAGetLastError() << std::endl; WSACleanup(); return 1; } // 设置NTP服务器地址和端口 SOCKADDR_IN serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(123); serverAddr.sin_addr.s_addr = inet_addr("time.nist.gov"); // 构造NTP请求报文 char ntpPacket[48] = {0}; ntpPacket[0] = 0x1b; // 发送NTP请求 iResult = sendto(sock, ntpPacket, sizeof(ntpPacket), 0, (SOCKADDR *)&serverAddr, sizeof(serverAddr)); if (iResult == SOCKET_ERROR) { std::cout << "sendto failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); WSACleanup(); return 1; } // 接收NTP响应 char recvBuf[1024] = {0}; iResult = recv(sock, recvBuf, sizeof(recvBuf), 0); if (iResult == SOCKET_ERROR) { std::cout << "recv failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); WSACleanup(); return 1; } // 解析NTP响应 unsigned long long ntpTime = 0; memcpy(&ntpTime, &recvBuf[40], sizeof(ntpTime)); ntpTime = ntohl(ntpTime); ntpTime -= NTP_TIMESTAMP_DELTA; time_t unixTime = (time_t)ntpTime; std::cout << "Current time is " << ctime(&unixTime) << std::endl; // 关闭套接字并清理 closesocket(sock); WSACleanup(); return 0; } ``` 此代码使用了time.nist.gov作为NTP服务器,您可以根据需要更改。需要注意的是,NTP协议使用的是UTC时间,因此需要进行时区转换。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值