我正在尝试更好地学习 NTP 协议,但我在编写的一些测试代码中遇到了一个奇怪的问题,编译后第一对运行似乎运行良好,但之后无法返回值.我意识到这是一个游泳池,但它似乎可以立即工作或根本不工作。我认为我的内存管理不是问题,每次运行后我都运行 MD5sums 以确保我没有破坏二进制文件。如果我应该设置更多字段,我从稀疏文档中有点不清楚。有什么我应该设置的吗?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#define NTP_PORT 123
#define NTP_TIMESTAMP_DELTA 2208988800ull
// NTP packet structure
typedef struct {
uint8_t li_vn_mode; // LI (0-1), VN (2-4), Mode (5-7)
uint8_t stratum; // Stratum
uint8_t poll; // Poll
uint8_t precision; // Precision
uint32_t root_delay; // Root Delay
uint32_t root_dispersion; // Root Dispersion
uint32_t ref_id; // Reference Identifier
uint32_t ref_ts_sec; // Reference Timestamp
uint32_t ref_ts_frac; // Reference Timestamp Fraction
uint32_t orig_ts_sec; // Origin Timestamp
uint32_t orig_ts_frac; // Origin Timestamp Fraction
uint32_t rx_ts_sec;
uint32_t rx_ts_frac;
uint32_t tx_ts_sec;
uint32_t tx_ts_frac;
} ntp_packet;
// Create and send an NTP request to the specified server
int ntp_request(const char* server, ntp_packet* packet) {
struct addrinfo hints, *res, *p;
int status;
char ipstr[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((status = getaddrinfo(server, NULL, &hints, &res)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}
printf("IP address for %s:\n\n", server);
for(p = res; p != NULL; p = p->ai_next)
{
void *addr;
size_t sz = 5;
char ipver[sz];
if (p->ai_family == AF_INET)
{
struct sockaddr_in *ipv4 = (struct sockaddr_in *) p->ai_addr;
addr = &(ipv4->sin_addr);
memcpy(&ipver, "IPv4", sz);
}
else
{
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
memcpy(&ipver, "IPv6", sz);
}
inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
printf(" %s: %s\n", ipver, ipstr);
}
int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0) {
perror("Failed to create socket");
return -1;
}
// Set the NTP server address and port
struct sockaddr_in servaddr;
servaddr.sin_family = res->ai_family;
servaddr.sin_port = htons(NTP_PORT);
if (inet_aton(ipstr, &servaddr.sin_addr) == 0) {
perror("Invalid server address");
return -1;
}
// Send the NTP request
memset(packet, 0, sizeof(ntp_packet));
// NTP version 3, client mode, unauthenticated (00 011 011)
packet->li_vn_mode = 0x1b;
if (sendto(sockfd, packet, sizeof(ntp_packet), 0, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
perror("Failed to send NTP request");
return -1;
}
// Receive the NTP response
memset(packet, 0, sizeof(ntp_packet));
socklen_t addrlen = sizeof(servaddr);
if (recvfrom(sockfd, packet, sizeof(ntp_packet), 0, (struct sockaddr*)&servaddr, &addrlen) < 0) {
perror("Failed to receive NTP response");
return -1;
}
freeaddrinfo(res);
close(sockfd);
return 0;
}
int main() {
const char* server = "pool.ntp.org";
ntp_packet packet;
// Send an NTP request to the server
if (ntp_request(server, &packet) < 0) {
return -1;
}
// Process the NTP response and calculate the current time
uint32_t ntp_timestamp = ntohl(packet.tx_ts_sec) - NTP_TIMESTAMP_DELTA;
time_t current_time = (time_t)ntp_timestamp;
printf("NTP server: %s\n", server);
printf("NTP timestamp: %u\n", ntp_timestamp);
printf("Current time: %s\n", ctime(¤t_time));
return 0;
}