需要sudo执行
#include <iostream>
#include <cstring>
#include <ctime>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <endian.h>
#include <iomanip>
struct NTPPacket {
uint8_t li_vn_mode;
uint8_t stratum;
uint8_t poll;
uint8_t precision;
uint32_t rootDelay;
uint32_t rootDispersion;
uint32_t refId;
uint64_t refTs;
uint64_t originTs;
uint64_t recvTs;
uint64_t transTs;
};
// 正确的 NTP 时间戳转换(处理字节序)
time_t ntp_to_unix(uint64_t ntp_ts) {
// 关键:将网络字节序转换为主机字节序
uint64_t host_ts = be64toh(ntp_ts);
// 提取秒部分(高32位)
uint32_t seconds = host_ts >> 32;
// 减去 NTP epoch (1900) 到 Unix epoch (1970) 的秒数
return (time_t)(seconds - 2208988800UL);
}
// 打印字节序转换后的值
void print_packet_info(const NTPPacket& packet, bool is_big_endian) {
std::cout << "\n=== NTP Packet Details ===" << std::endl;
// 1. 第一个字节的解析
std::cout << "LI-VN-Mode: 0x" << std::hex << std::setw(2) << std::setfill('0')
<< (int)packet.li_vn_mode << std::dec << std::setfill(' ');
uint8_t mode = packet.li_vn_mode & 0x07;
uint8_t version = (packet.li_vn_mode >> 3) & 0x07;
uint8_t leap = (packet.li_vn_mode >> 6) & 0x03;
std::cout << " (Leap=" << (int)leap << ", Version=" << (int)version
<< ", Mode=" << (int)mode << ")";
if (mode == 4) std::cout << " [Server Response]";
else if (mode == 3) std::cout << " [Client Request]";
std::cout << std::endl;
// 2. Stratum(层级)
std::cout << "Stratum: " << (int)packet.stratum;
if (packet.stratum == 0) std::cout << " (unspecified)";
else if (packet.stratum == 1) std::cout << " (primary reference)";
else std::cout << " (secondary reference)";
std::cout << std::endl;
// 3. Poll(轮询间隔)
std::cout << "Poll: " << (int)packet.poll << " (2^" << (int)packet.poll << " = "
<< (1 << packet.poll) << " seconds)" << std::endl;
// 4. Precision(精度)
std::cout << "Precision: " << (int)packet.precision << " (2^" << (int)packet.precision
<< " = " << (1.0 / (1 << (-packet.precision))) << " seconds)" << std::endl;
// 5. Root Delay(根延迟)
uint32_t rootDelay = ntohl(packet.rootDelay);
std::cout << "Root Delay: 0x" << std::hex << std::setw(8) << std::setfill('0')
<< packet.rootDelay << std::dec << std::setfill(' ');
std::cout << " (" << (rootDelay / 65536.0) << " seconds)" << std::endl;
// 6. Root Dispersion(根离散度)
uint32_t rootDisp = ntohl(packet.rootDispersion);
std::cout << "Root Dispersion: 0x" << std::hex << std::setw(8) << std::setfill('0')
<< packet.rootDispersion << std::dec << std::setfill(' ');
std::cout << " (" << (rootDisp / 65536.0) << " seconds)" << std::endl;
// 7. Reference ID(参考ID)
std::cout << "Reference ID: 0x" << std::hex << std::setw(8) << std::setfill('0')
<< ntohl(packet.refId) << std::dec << std::setfill(' ');
// 尝试作为IP地址解析
uint32_t refId = ntohl(packet.refId);
if (refId >= 0x01000000 && refId <= 0xFE000000) {
struct in_addr addr;
addr.s_addr = packet.refId;
std::cout << " (IP: " << inet_ntoa(addr) << ")";
} else {
// 可能是4个字符的ID
char ref[5];
memcpy(ref, &packet.refId, 4);
ref[4] = '\0';
std::cout << " (Code: " << ref << ")";
}
std::cout << std::endl;
// 8. 时间戳(重点!)
auto print_timestamp = [](const char* name, uint64_t ts) {
// 原始值
std::cout << name << " (raw): 0x" << std::hex << std::setw(16) << std::setfill('0')
<< ts << std::dec << std::setfill(' ');
// 转换为正确的时间
uint64_t host_ts = be64toh(ts);
uint32_t seconds = host_ts >> 32;
uint32_t fraction = host_ts & 0xFFFFFFFF;
if (seconds > 0) {
time_t t = seconds - 2208988800UL;
std::cout << " => " << ctime(&t);
std::cout << " Fraction: 0x" << std::hex << std::setw(8) << std::setfill('0')
<< fraction << std::dec << std::setfill(' ');
std::cout << " (" << (fraction / 4294967296.0 * 1000000) << " microseconds)" << std::endl;
} else {
std::cout << " (zero)" << std::endl;
}
};
std::cout << "\n--- Timestamps ---" << std::endl;
print_timestamp("Reference Timestamp", packet.refTs);
print_timestamp("Origin Timestamp", packet.originTs);
print_timestamp("Receive Timestamp", packet.recvTs);
print_timestamp("Transmit Timestamp", packet.transTs);
// 9. 计算出网络延迟和偏差(如果有Origin和Receive时间)
if (packet.originTs != 0 && packet.recvTs != 0) {
uint64_t origin_host = be64toh(packet.originTs);
uint64_t recv_host = be64toh(packet.recvTs);
uint64_t trans_host = be64toh(packet.transTs);
uint32_t origin_sec = origin_host >> 32;
uint32_t recv_sec = recv_host >> 32;
uint32_t trans_sec = trans_host >> 32;
if (origin_sec > 0 && recv_sec > 0 && trans_sec > 0) {
time_t t1 = origin_sec - 2208988800UL;
time_t t2 = recv_sec - 2208988800UL;
time_t t3 = trans_sec - 2208988800UL;
double origin_f = (origin_host & 0xFFFFFFFF) / 4294967296.0;
double recv_f = (recv_host & 0xFFFFFFFF) / 4294967296.0;
double trans_f = (trans_host & 0xFFFFFFFF) / 4294967296.0;
double origin_time = origin_sec + origin_f;
double recv_time = recv_sec + recv_f;
double trans_time = trans_sec + trans_f;
// 简单计算:假设客户端发送时间和接收时间对称
std::cout << "\n--- Network Statistics ---" << std::endl;
std::cout << "Client send time: " << std::fixed << std::setprecision(3) << origin_time << std::endl;
std::cout << "Server receive time: " << recv_time << std::endl;
std::cout << "Server transmit time: " << trans_time << std::endl;
// 往返延迟 = (当前时间 - 发送时间) - (服务器处理时间)
// 这里简化计算
time_t now;
time(&now);
double rtt = (now + 0.0) - origin_time;
std::cout << "Estimated RTT: " << rtt << " seconds" << std::endl;
}
}
std::cout << "===========================" << std::endl;
}
// 打印原始字节数据(十六进制)
void print_raw_data(const uint8_t* data, size_t len) {
std::cout << "\n=== Raw Packet Data (Hex) ===" << std::endl;
for (size_t i = 0; i < len; i++) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)data[i] << " ";
if ((i + 1) % 16 == 0) {
std::cout << " ";
// 打印ASCII
for (size_t j = i - 15; j <= i; j++) {
if (data[j] >= 32 && data[j] <= 126) {
std::cout << (char)data[j];
} else {
std::cout << ".";
}
}
std::cout << std::endl;
}
}
if (len % 16 != 0) {
// 补全最后的ASCII
size_t last_start = (len / 16) * 16;
for (size_t j = last_start; j < len; j++) {
if (data[j] >= 32 && data[j] <= 126) {
std::cout << (char)data[j];
} else {
std::cout << ".";
}
}
std::cout << std::endl;
}
std::cout << std::dec << std::setfill(' ');
std::cout << "=============================" << std::endl;
}
// 改进版:获取时间并正确处理字节序
bool get_time_via_ntp(const char* server, time_t& outTime) {
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0) return false;
struct sockaddr_in serverAddr;
struct hostent *serverHost = gethostbyname(server);
if (serverHost == nullptr) {
close(sockfd);
return false;
}
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(123);
memcpy(&serverAddr.sin_addr, serverHost->h_addr_list[0], serverHost->h_length);
// 设置超时
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
NTPPacket packet;
memset(&packet, 0, sizeof(packet));
packet.li_vn_mode = 0x1B; // NTP 请求
if (sendto(sockfd, &packet, sizeof(packet), 0,
(struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
close(sockfd);
return false;
}
socklen_t addrLen = sizeof(serverAddr);
if (recvfrom(sockfd, &packet, sizeof(packet), 0,
(struct sockaddr*)&serverAddr, &addrLen) < 0) {
close(sockfd);
return false;
}
close(sockfd);
// 调试输出:打印原始时间戳(可选)
std::cout << "Raw timestamp: 0x" << std::hex << packet.transTs << std::dec << std::endl;
// 打印原始数据
print_raw_data((const uint8_t*)&packet, addrLen);
// 打印解析后的字段
print_packet_info(packet, true);
outTime = ntp_to_unix(packet.transTs);
// 验证时间合理性(应该在 2020-2030 之间)
if (outTime < 1577836800 || outTime > 1893456000) { // 2020-2030
std::cout << " Warning: suspicious time: " << ctime(&outTime);
return false;
}
return true;
}
// 备用方案:使用多个服务器并返回成功
bool get_time_with_fallback(time_t& outTime) {
const char* servers[] = {
"ntp.aliyun.com",
"ntp1.aliyun.com",
"ntp.tencent.com",
"pool.ntp.org",
"cn.pool.ntp.org",
"time.google.com"
};
for (int i = 0; i < 6; i++) {
std::cout << " Testing: " << servers[i] << " ... ";
if (get_time_via_ntp(servers[i], outTime)) {
std::cout << "SUCCESS" << std::endl;
return true;
}
std::cout << "FAILED" << std::endl;
}
return false;
}
int main() {
time_t syncTime = 0;
std::cout << "=== NTP Time Sync (Fixed Endian) ===" << std::endl;
if (!get_time_with_fallback(syncTime)) {
std::cerr << "\nAll NTP servers failed." << std::endl;
return 1;
}
// 验证时间
struct tm* tm_info = localtime(&syncTime);
if (tm_info->tm_year < 120 || tm_info->tm_year > 130) { // 2020-2030
std::cerr << "Warning: Time seems incorrect: " << ctime(&syncTime);
std::cerr << "Please check your system's timezone settings." << std::endl;
}
// 设置系统时间
struct timeval tv;
tv.tv_sec = syncTime;
tv.tv_usec = 0;
if (settimeofday(&tv, nullptr) < 0) {
perror("Failed to set system time (need sudo)");
return 1;
}
std::cout << "\n✓ System time updated to: " << ctime(&syncTime);
// 显示当前时间
time_t now;
time(&now);
std::cout << "Current system time: " << ctime(&now);
return 0;
}