美好的一天,
背景:我几乎完全使用C,汇编和shell脚本。 一般来说,我很less使用C ++,JAVA或OOdevise。
我正在尝试实现一个非常基本的NTP客户端,以便我可以查询远程NTP服务器(即: pool.ntp.org
)的Internet时间,以便在每次启动时自动设置Windows开发板上的时间。
我从另一个用户在这里重构了代码:
用sntp从服务器获取时间/date(windows c ++)
但程序挂在recv()
操作。 DNSparsing和send()
操作似乎执行没有任何问题。
有谁知道我在哪里可以find一个简单的Windows NTP客户端示例(GPL是首选,但任何事情都可以在这一点上),或者他们可以评论为什么下面的代码块会挂起这个例子(我不应该说“挂起“,它似乎从来没有收到回应)。
NTP_CLIENT.CPP
/****************************************************************************** * Project Headers *****************************************************************************/ #include "stdafx.h" #include "ntp_client.h" /****************************************************************************** * System Headers *****************************************************************************/ #include <winsock2.h> #include <winsock.h> #include <ws2tcpip.h> /****************************************************************************** * Preprocessor Directives and Macros *****************************************************************************/ /****************************************************************************** * Class Member Function Definitions *****************************************************************************/ void Timestamp::ReverseEndian(void) { ReverseEndianInt(seconds); ReverseEndianInt(fraction); } time_t Timestamp::to_time_t(void) { return (seconds - ((70 * 365 + 17) * 86400))&0x7fffffff; } void NTPMessage::ReverseEndian(void) { ref.ReverseEndian(); orig.ReverseEndian(); rx.ReverseEndian(); tx.ReverseEndian(); } int NTPMessage::recv(int sock) { int ret = ::recv(sock, (char*)this, sizeof(*this), 0); ReverseEndian(); return ret; } int NTPMessage::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; } void NTPMessage::clear() { memset(this, 0, sizeof(*this)); }
NTP_CLIENT.H
#ifndef __NTP_CLIENT_H__ #define __NTP_CLIENT_H__ #include <ctime> #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(void); /** * 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(void); }; /** * 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(void); /** * Recieve an NTPMessage. * Overwrites this object with values from the received packet. */ int recv(int sock); /** * Send an NTPMessage. */ int sendto(int sock, struct sockaddr_in* srv_addr); /** * Zero all the values. */ void clear(); }; #endif /* __NTP_CLIENT_H__ */
被测设备上的防火墙和防病毒软件已被禁用。
谢谢。
编辑
按要求,这是主体的main
:
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();
参考
从RFC 5905的图8(将需要向下滚动到第18页):
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |LI | VN |Mode | Stratum | Poll | Precision | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
我在图8中看到的一件事是模式,版本和跳跃应该组成第一个字节。
将模式,版本和跳转类型从unsigned int
更改为unsigned char
以便您的按位变量只跨越1个字节而不是4个。这将使您的NTPMessage大小预期为48个字节。
喜欢:
struct NTPMessage { unsigned char mode :3; unsigned char version :2; unsigned char leap :2; ...