You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux环境C++编写NTP客户端运行后无返回数据该如何解决?

问题原因
  • 核心原因:未发送NTP请求报文:NTP采用请求-响应交互模式,UDP本身无连接状态,你调用的UDP connect 仅在内核层面绑定了对端地址端口,不会触发任何网络交互。你没有主动向服务端发送标准NTP请求,服务端不会主动向你推送时间数据,导致recv系统调用一直阻塞等待数据。
  • 未设置接收超时:默认情况下套接字接收是永久阻塞模式,没有数据到达时会一直等待,不会主动超时退出。
  • 额外问题:返回值解析错误:NTP返回的是二进制格式的时间报文,不是可打印字符串,直接用std::cout输出pack只会得到乱码,无法得到可读时间。
修复步骤
  1. 构造标准NTP请求包:NTP请求报文固定为48字节,首字节填0x1B(表示版本号4、客户端模式),剩余47字节初始化为0即可。
  2. 发送请求包后再调用recv接收响应。
  3. 给套接字设置接收超时,避免永久阻塞。
  4. 解析返回的二进制NTP时间戳,转换为可读的本地时间。
修复后完整代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <iostream>
#include <string.h>
#include <arpa/inet.h>
#include <ctime>

int main(int argc, char *argv[])
{
    int sock;
    int recvsize;
    // NTP报文固定为48字节
    char pack[48] = {0};

    struct sockaddr_in sAddr;
    struct hostent *sHost;

    sHost = gethostbyname("time.google.com");
    if(sHost == NULL){
        perror("gethostbyname error");
        return 0;
    }

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sock < 0) {
        perror("socket create error");
        return -1;
    }

    // 设置5秒接收超时,避免永久阻塞
    struct timeval timeout = {5, 0};
    if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
        perror("setsockopt error");
        close(sock);
        return -1;
    }

    memset(&sAddr, 0, sizeof(sAddr));
    sAddr.sin_family = AF_INET;

    memcpy(&sAddr.sin_addr, sHost->h_addr_list[0], sizeof(sAddr.sin_addr));
    sAddr.sin_port = htons(123);

    if(connect(sock, (struct sockaddr*)&sAddr, sizeof(sAddr)) == -1){
        perror("connect error");
        close(sock);
        return -1;
    }

    std::cout << "Connect success, sending NTP request..." << std::endl;

    // 构造NTP请求包,首字节为0x1B,其余为0
    pack[0] = 0x1B;
    if(send(sock, pack, sizeof(pack), 0) < 0) {
        perror("send request error");
        close(sock);
        return -1;
    }

    recvsize = recv(sock, pack, sizeof(pack), 0);
    if(recvsize < 0) {
        perror("recv error, maybe timeout");
        close(sock);
        return -1;
    }

    std::cout << "Get response size: " << recvsize << std::endl;

    // 解析NTP时间戳,偏移40字节的位置是传输时间戳的秒数部分
    uint32_t ntp_time = ntohl(*(uint32_t*)&pack[40]);
    // NTP时间起始是1900-01-01,Unix时间起始是1970-01-01,相差2208988800秒
    time_t unix_time = ntp_time - 2208988800ULL;
    std::cout << "Current time: " << ctime(&unix_time) << std::endl;
    
    close(sock);
    return 0;
}
额外注意事项
  • 运行前请确认VirtualBox的Ubuntu虚拟机网络正常,能访问公网,且没有防火墙拦截123端口的UDP流量。
  • 若time.google.com访问不稳定,可以替换为国内NTP服务地址,比如ntp.aliyun.com。

内容的提问来源于stack exchange,提问作者tkm-knj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 19:45:02