首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用sntp从服务器获取时间/日期(windows c++)

使用sntp从服务器获取时间/日期(windows c++)
EN

Stack Overflow用户
提问于 2012-10-22 20:31:23
回答 2查看 13.7K关注 0票数 5

我正在寻找一个c/c++的工作代码,它可以从服务器(ntp.belnet.be)获取时间和日期。它使用UDP并使用端口123。

有人能帮帮忙吗?

代码语言:javascript
复制
//sending pakket
memset(&sntp_msg_header, 0, sizeof sntp_msg_header);
sntp_msg_header.flags = 27;
sntp_msg_header.originate_timestamp_secs = time(NULL);

// Get data in rxmsg
...
...

// print time
timeval = ntohl(rxmsg.transmit_timestamp_secs) - ((70ul * 365ul + 17ul) * 86400ul);
printf("%s", ctime(&timeval));

这就是我到目前为止所拥有的。但我不能从中得到正确的数据。我希望这是更多的信息。

如果找到以下内容:

代码语言:javascript
复制
import socket
import struct
import sys
import time

TIME1970 = 2208988800L      # Thanks to F.Lundh

client = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
data = '\x1b' + 47 * '\0'
client.sendto( data, ( sys.argv[1], 123 ))
data, address = client.recvfrom( 1024 )
if data:
    print 'Response received from:', address
    t = struct.unpack( '!12I', data )[10]
    t -= TIME1970
    print '\tTime=%s' % time.ctime(t)

但它是用python编写的。有没有人能把它改成c++,或者有没有这样的转换器?

EN

回答 2

Stack Overflow用户

发布于 2012-11-28 02:05:44

这就是我所使用的。它不是很优雅,但它应该足以让人理解这个想法。基本思想是拥有一个与网络发送和接收的内容相匹配的结构。颠倒的字节顺序最初并不明显。值得一提的是,对于错误情况,这几乎没有什么用处。你会想解决这个问题的。:)

代码语言:javascript
复制
#define ReverseEndianInt(x) ((x) = \
    ((x)&0xff000000) >> 24 |\
    ((x)&0x00ff0000) >> 8 |\
    ((x)&0x0000ff00) << 8 |\
    ((x)&0x000000ff) << 24)

/**
 * NTP Fixed-Point Timestamp Format.
 * From [RFC 5905](http://tools.ietf.org/html/rfc5905).
 */
struct Timestamp
{
    unsigned int seconds; /**< Seconds since Jan 1, 1900. */
    unsigned int fraction; /**< Fractional part of seconds. Integer number of 2^-32 seconds. */

    /**
     * Reverses the Endianness of the timestamp.
     * Network byte order is big endian, so it needs to be switched before
     * sending or reading.
     */
    void ReverseEndian() {
        ReverseEndianInt(seconds);
        ReverseEndianInt(fraction);
    }

    /**
     * Convert to time_t.
     * Returns the integer part of the timestamp in unix time_t format,
     * which is seconds since Jan 1, 1970.
     */
    time_t to_time_t()
    {
        return (seconds - ((70 * 365 + 17) * 86400))&0x7fffffff;
    }
};

/**
 * A Network Time Protocol Message.
 * From [RFC 5905](http://tools.ietf.org/html/rfc5905).
 */
struct NTPMessage
{
    unsigned int mode :3; /**< Mode of the message sender. 3 = Client, 4 = Server */
    unsigned int version :2; /**< Protocol version. Should be set to 3. */
    unsigned int leap :2; /**< Leap seconds warning. See the [RFC](http://tools.ietf.org/html/rfc5905#section-7.3) */
    unsigned char stratum; /**< Servers between client and physical timekeeper. 1 = Server is Connected to Physical Source. 0 = Unknown. */
    unsigned char poll; /**< Max Poll Rate. In log2 seconds. */
    unsigned char precision; /**< Precision of the clock. In log2 seconds. */
    unsigned int sync_distance; /**< Round-trip to reference clock. NTP Short Format. */
    unsigned int drift_rate; /**< Dispersion to reference clock. NTP Short Format. */
    unsigned char ref_clock_id[4]; /**< Reference ID. For Stratum 1 devices, a 4-byte string. For other devices, 4-byte IP address. */
    Timestamp ref; /**< Reference Timestamp. The time when the system clock was last updated. */
    Timestamp orig; /**< Origin Timestamp. Send time of the request. Copied from the request. */
    Timestamp rx; /**< Recieve Timestamp. Reciept time of the request. */
    Timestamp tx; /**< Transmit Timestamp. Send time of the response. If only a single time is needed, use this one. */


    /**
     * Reverses the Endianness of all the timestamps.
     * Network byte order is big endian, so they need to be switched before
     * sending and after reading.
     *
     * Maintaining them in little endian makes them easier to work with
     * locally, though.
     */
    void ReverseEndian() {
        ref.ReverseEndian();
        orig.ReverseEndian();
        rx.ReverseEndian();
        tx.ReverseEndian();
    }

    /**
     * Recieve an NTPMessage.
     * Overwrites this object with values from the recieved packet.
     */
    int recv(int sock)
    {
        int ret = ::recv(sock, (char*)this, sizeof(*this), 0);
        ReverseEndian();
        return ret;
    }

    /**
     * Send an NTPMessage.
     */
    int sendto(int sock, struct sockaddr_in* srv_addr)
    {
        ReverseEndian();
        int ret = ::sendto(sock, (const char*)this, sizeof(*this), 0, (sockaddr*)srv_addr, sizeof(*srv_addr));
        ReverseEndian();
        return ret;
    }

    /**
     * Zero all the values.
     */
    void clear()
    {
        memset(this, 0, sizeof(*this));
    }
};

您可能会这样使用它,也许是在main()中。

代码语言:javascript
复制
WSADATA wsaData;
DWORD ret = WSAStartup(MAKEWORD(2,0), &wsaData);

char *host = "pool.ntp.org"; /* Don't distribute stuff pointing here, it's not polite. */
//char *host = "time.nist.gov"; /* This one's probably ok, but can get grumpy about request rates during debugging. */

NTPMessage msg;
/* Important, if you don't set the version/mode, the server will ignore you. */
msg.clear();
msg.version = 3;
msg.mode = 3 /* client */;

NTPMessage response;
response.clear();

int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in srv_addr;
memset(&srv_addr, 0, sizeof(srv_addr));
dns_lookup(host, &srv_addr); /* Helper function defined below. */

msg.sendto(sock, &srv_addr);
response.recv(sock);

time_t t = response.tx.to_time_t();
char *s = ctime(&t);
printf("The time is %s.", s);

WSACleanup();

有很多方法可以获取ip和端口,但getaddrinfo在Windows上做得很好:

代码语言:javascript
复制
int dns_lookup(const char *host, sockaddr_in *out)
{
    struct addrinfo *result;
    int ret = getaddrinfo(host, "ntp", NULL, &result);
    for (struct addrinfo *p = result; p; p = p->ai_next)
    {
        if (p->ai_family != AF_INET)
            continue;

        memcpy(out, p->ai_addr, sizeof(*out));
    }
    freeaddrinfo(result);
}

当然,这个解决方案就像搁浅的鲸鱼一样轻便,但它适用于我的™。

票数 6
EN

Stack Overflow用户

发布于 2012-10-22 20:52:24

与大多数其他语言相比,C/++中的套接字并不那么令人愉快,尤其是在解释语言和较新的编译语言中。

为什么不使用

  • http://ntp.org/downloads.html

当然,NTP需要MinGW,但也有一些库。

  • http://www.hillstone-software.com/hs_ntp_details.htm (它不是免费的,但可以免费尝试,而且不是必需的)

从server 2000版本开始,Windows还内置了NTP。我不能验证它,但它应该至少在Vista以后的系统上工作。

  • w32tm /help (查找section)
  • More文档:http://technet.microsoft.com/en-us/library/cc773263%28v=ws.10%29.aspx

/query

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13011532

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档