Visual C ++中的Windows中的基本NTP客户端 [英] Basic NTP Client in Windows in Visual C++

查看:236
本文介绍了Visual C ++中的Windows中的基本NTP客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

美好的一天,



背景:我几乎完全使用C,汇编和shell脚本。我一般很少使用C ++,JAVA或OO设计。



我试图实现一个非常基本的NTP客户端,所以我可以查询远程NTP服务器 pool.ntp.org )的互联网时间自动设置每次启动时Windows开发板上的时间。



我已从其他用户重构了此处的代码:



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



但是程序挂起在 recv()操作。 DNS解析和 send()操作似乎执行没有任何问题。



有人知道我在哪里可以找到一个简单的NTP客户端示例在Windows(GPL是首选,但任何事情在这一点上),或者他们可以评论为什么以下代码块将挂起的示例(我不应该说挂起,它从来不会出现



 

code> / ******************************************** **********************************
*项目标题
***** **************************************************** ********************** /
#includestdafx.h
#includentp_client.h

/ ********************************************** ********************************
*系统标题
******* **************************************************** ******************** /
#include< winsock2.h>
#include< winsock.h>
#include< ws2tcpip.h>


/ *********************************** *****************************************
*预处理程序指令和宏
********************************************** ******************************* /


/ ***** **************************************************** ***********************
*类成员函数定义
*************** **************************************************** ************* /
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
$ b

  #ifndef __NTP_CLIENT_H__ 
#define __NTP_CLIENT_H__

#include< ctime>

#define ReverseEndianInt(x)((x)= \
((x)& 0xff000000)>> 24 | \
; 0x00ff0000)>> 8 | \
((x)& 0x0000ff00)<8 | \
((x)& 0x000000ff)<24)

/ **
* NTP定时点时间戳格式。
* From [RFC 5905](http://tools.ietf.org/html/rfc5905)。
* /
struct Timestamp {
unsigned int seconds; / **<从1900年1月1日起的秒数。* /
unsigned int fraction; / **<秒的小数部分。整数为2 ^ -32秒。 * /

/ **
*反转时间戳的字节序。
*网络字节顺序是大端,所以需要在
*发送或读取之前切换。
* /
void ReverseEndian(void);

/ **
*转换为time_t。
*返回unix time_t格式的时间戳记的整数部分,
*是1970年1月1日以来的秒数。
* /
time_t to_time_t(void);
};

/ **
*网络时间协议消息。
* From [RFC 5905](http://tools.ietf.org/html/rfc5905)。
* /
struct NTPMessage {
unsigned int mode:3; / **<消息发送方的模式。 3 =客户端,4 =服务器* /
unsigned int版本:2; / **<协议版本。应该设置为3. * /
unsigned int leap:2; / **<闰秒警告。参见[RFC](http://tools.ietf.org/html/rfc5905#section-7.3)* /
unsigned char stratum; / **<客户端和物理计时器之间的服务器。 1 =服务器已连接到物理来源。 0 =未知。 * /
unsigned char poll; / **<最高投票率。在log2秒。 * /
unsigned char precision; / **<时钟的精度。在log2秒。 * /
unsigned int sync_distance; / **<往返参考时钟。 NTP短格式。 * /
unsigned int drift_rate; / **<分散到参考时钟。 NTP短格式。 * /
unsigned char ref_clock_id [4]; / **<参考ID。对于Stratum 1设备,为4字节字符串。对于其他设备,4字节的IP地址。 * /
Timestamp ref; / **<参考时间戳。上次更新系统时钟的时间。 * /
Timestamp orig; / **<原始时间戳。发送请求的时间。从请求中复制。 * /
Timestamp rx; / **<接收时间戳。请求的回复时间。 * /
Timestamp tx; / **<发送时间戳。发送响应的时间。如果只需要一个时间,使用这一个。 * /


/ **
*反转所有时间戳的字节顺序。
*网络字节顺序是大端,所以他们需要在
*发送之前和读取后切换。
*
*保持它们在小端,使他们更容易使用本地
*。
* /
void ReverseEndian(void);

/ **
*接收NTPMessage。
*使用接收到的数据包中的值覆盖此对象。
* /
int recv(int sock);

/ **
*发送NTPMessage。
* /
int sendto(int sock,struct sockaddr_in * srv_addr);

/ **
*清零所有值。
* /
void clear();
};

#endif / * __NTP_CLIENT_H__ * /

防火墙和防病毒软件



编辑






根据需要,这是 main 的正文:

  WSADATA wsaData; 
DWORD ret = WSAStartup(MAKEWORD(2,0),& wsaData);

char * host =pool.ntp.org; / *不要分发在这里指向的东西,它不礼貌。 * /
// char * host =time.nist.gov; / *这个可能是确定的,但可以在调试期间对请求率感到脾气暴躁。 * /

NTPMessage msg;
/ *重要的是,如果你不设置版本/模式,服务器会忽略你。 * /
msg.clear();
msg.version = 3;
msg.mode = 3 / * client * /;

NTPMessage响应;
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); / *辅助函数定义如下。 * /

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

时间t t = response.tx.to_time_t();
char * s = ctime(& t);
printf(时间是%s。,s);

WSACleanup();






参考 p>


  1. 使用sntp(Windows c ++)从服务器获取时间/日期


解决方案

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
+ - + - + - + - + - + - + - + - + - + - + - + - + - - + - + - + - + - + - + - + - + - + - + - + - + - VN | Mode | Stratum |投票|精度|
+ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +



我在图8中看到的是,模式,版本和跳跃应该组成第一个字节。



将模式,版本和闰域类型从 unsigned int 更改为 unsigned char ,因此您的逐位变量只能跨越1个字节而不是4个。这将使您的NTPMessage大小为预期的48个字节。



like:

  struct NTPMessage {
unsigned char mode:3;
unsigned char版本:2;
unsigned char leap:2;
...


Good day,

Background: I work almost exclusively with C, assembly, and shell scripting. I seldom use C++, JAVA, or OO design in general.

I am attempting to implement a very basic NTP client just so I can query a remote NTP server (ie: pool.ntp.org) for the internet time to automatically set the time on my Windows development board on each boot.

I've refactored the code here from another user:

Get time/date from server with sntp(windows c++)

But the program hangs at the recv() operation. The DNS resolution and send() operations appear to execute without any issues.

Does anyone know where I can find a simple NTP client example in Windows (GPL is preferred, but anything would do at this point), or can they comment on why the following code block would hang from the example (I shouldn't say "hang", it just never appears to receive a response).

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__ */

Firewall and antivirus software has been disabled on the device under test.

Thank you.

EDIT


As requested, this is the body of 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();


References

  1. Get time/date from server with sntp(windows c++)

解决方案

From Figure 8 of RFC 5905 (will need to scroll down to page 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   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

One thing I see in figure 8 is that mode, version, and leap should compose the first byte.

Change mode, version, and leap types from unsigned int to unsigned char so your bitwise variables only span 1 byte instead of 4. This will make your NTPMessage size the expected 48 bytes.

like:

struct NTPMessage {
    unsigned char mode :3;
    unsigned char version :2;
    unsigned char leap :2;
    ...

这篇关于Visual C ++中的Windows中的基本NTP客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆