C + + uses boost to implement network time Protocol (NTP) clients

Source: Internet
Author: User
Tags local time

cited words

I installed two systems on the machine, one Linux Ubuntu, one Windows8.1. The depressing thing is that every time you restart from Ubuntu into Windows, the system time is always less than 8 hours, each time with the Windows program to synchronize, which is the following:

This thing is actually an NTP Client, select an NTP Server from the Internet, get UTC time, and then set the local time.

So I want to implement a program like this, Baidu first, there are a lot of information on the NTP and implementation code, mostly a single platform, not cross-platform

, here are a few references:

http://blog.csdn.net/loongee/article/details/24271129

http://blog.csdn.net/chexlong/article/details/6963541

Http://www.cnblogs.com/TianFang/archive/2011/12/20/2294603.html

This article uses the boost ASIO to implement NTP Client across platforms.

Get ready

1. The latest boost library, this article uses the 1.56.0 version

To use the ASIO network library inside.

2. IDE is visual Studio with Update3

The author is the version of the emperor

3. Wireshark is also the latest 1.12.1 version

NTP Client to analyze Windows comes with

NTP Packet Analysis

Here we analyze is that program, click Update Now, will send the request packet NTP, the following is the Wireshark capture results:

You can get some of the following information:

    1. NTP time synchronization is divided into two processes, a request, a response

    2. The IP address of the NTP server here is 129.6.15.28

    3. The program does not have DNS resolution, it is possible to save the IP address directly

    4. The port number of the NTP service is 123,client also uses 123 Port , later found that the client is not bound to use the 123 port

    5. The NTP protocol is an application protocol built on the UDP transport protocol .

    6. The V3 version of the NTP protocol is used here, and there are V4

Well, with some basic information about the NTP protocol, let's take a look at the application tier details:

Response Package:

A lot of fields, about the meaning of each field, please refer to the above-mentioned link, this article mainly about implementation. Here Reference timestamp is the timestamp sent by the request package, and Origin,receive,transmit is returned from the server, the last three times are very small, so it's convenient to take a final transmit timestamp as a result.

? Coding ?

The compilation of the relevant libraries in boost can refer to the official documentation, which has a very simple example.

1. Required header files and namespaces

#include <iostream> #include "boost/asio.hpp" #include "boost/date_time/posix_time/posix_time.hpp" using Namespace boost::p osix_time;using namespace Boost::asio::ip;

2. Structure of the Ntppacket

Class ntppacket {public:    ntppacket ()  {         _rep._flags = 0xdb;        //     11.. ....    Leap Indicator: unknown     &NBSP;&NBSP;&NBSP;&NBSP;//&NBSP;&NBSP;&NBSP;&NBSP, .... 01 1...    ntp version 3        //     .... .011    Mode: client         _rep._pcs = 0x00;//unspecified        _ rep._ppt = 0x01;        _rep._pcp = 0x01;         _rep._rdy = 0x01000000;//big-endian         _rep._rdn = 0x01000000;    &nBsp;   _rep._rid = 0x00000000;        _rep._ ret = 0x0;        _rep._ort = 0x0;         _rep._rct = 0x0;         _rep._trt = 0x0;    }    friend std::ostream&  operator<< (Std::ostream& os, const ntppacket& ntpacket)  {         return os.write (reinterpret_cast<const char *> (& NTPACKET._REP),  sizeof (Ntpacket._rep)); &NBSP;&NBSP;&NBSP;&NBSP;}&NBSP;&NBSP;&NBSP;&NBSP;FRIEND&NBSP;STD:: Istream& operator>> (Std::istream& is, ntppacket& ntpacket)  {         return is.read (reinterpret_cast<char*> (&ntpacket._rep ),  sizeof (NTPACket._rep));     }public: #pragma  pack (1)     struct ntpheader  {        uint8_t _flags;//Flags         uint8_t _pcs;//Peer Clock Stratum         uint8_t _ppt;//Peer Polling Interval         uint8_t _pcp;//peer clock precision        uint32 _t _rdy;//root delay        uint32_t _rdn;//root  dispersion        uint32_t _rid;//reference id         uint64_t _ret;//Reference Timestamp         uint64_t _ort;//Origin Timestamp         uint64_t _rct;//receiVe timestamp        uint64_t _trt;//transmit timestamp     }; #pragma  pack ()     NtpHeader _rep;};

Here, in order to facilitate access, the struct is not placed in private, it is important to note that the structure of the various fields of the order and the need for memory 1-byte alignment, even with:

#pragma pack (1)

Memory alignment is important in network programming and directly affects the content of packet, which can be referenced in memory alignment:

Http://www.cppblog.com/cc/archive/2006/08/01/10765.html

The most important thing in the NTP request package is the flags, which contain version information that directly affects the content of the protocol work, and therefore cannot be mistaken.

Two operator overloads are used to facilitate the reading and writing of packet data.

Looking at the implementation of the client class, the main task of the client class is to send and receive the NTP packet and return the last 64bit timestamp.

Class ntpclient {public:    ntpclient (Const std::string& serverip)         :_socket (IO),  _serverip (ServerIP)  {     }    time_t gettime ()  {         if  (_socket.is_open ())  {             _socket.shutdown (UDP::SOCKET::SHUTDOWN_BOTH,&NBSP;_EC);             if  (_EC)  {                 std::cout << _ec.message ()  << std::endl;                 _socket.close ();                 return 0;             }             _socket.close ();        }         udp::endpoint ep (Boost::asio::ip::address_v4::from_string (_serverip),  NTP_PORT);         NtpPacket request;         std::stringstream ss;        std::string buf;         ss << request;         ss >> buf;        _socket.open (Udp::v4 ());         _socket.send_to (Boost::asio::buffer (BUF), &NBSP;EP);         std::array<uint8_t, 128> recv;         siZe_t len = _socket.receive_from (Boost::asio::buffer (recv), &NBSP;EP);         uint8_t* pbytes = recv.data ();         /****dump hex data        for  (size_t  i = 0; i < len; i++)  {        if   (i % 16 == 0)  {        std::cout  << std::endl;        }       &NBSP;&NBSP;ELSE&NBSP;{&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;STD::COUT&NBSP;&LT;&LT;&NBSP;STD::SETW ( 2)  << std::setfill (' 0 ')         << std::hex  <<  (uint32_t)  pBytes[i];        std::cout  <<  '   ';        }        }         ****/        time_t tt;         uint64_t last;         uint32_t seconds;        /****get the last 8  bytes (Transmit timestamp)  from received packet.         std::memcpy (&last, pbytes + len - 8, sizeof (last));         ****create a NtpPacket*/         ntppacket resonpse;        std::stringstream rss ;         rss.write (Reinterpret_cast<const char*> (pBytes),  len);         rss >> resonpse;         last = resonpse._rep._trt;        //         reversebyteorder (last);         seconds  =  (last & 0x7fffffff00000000)  >> 32;         tt = seconds + 8 * 3600 * 2 - 61533950;         return tt;    }private:     const uint16_t ntp_port = 123;    udp::socket _socket ;     std::string _serverip;    boost::system::error_code _ec ;};

Note several places:

1. Udp::socket is a socket using the UDP protocol in boost, and his construction requires a io_service,io_service that can be declared directly in the global zone:

Boost::asio::io_service io;

2. Create an address that endpoint uses to represent the NTP server:

Udp::endpoint EP (Boost::asio::ip::address_v4::from_string (_serverip), ntp_port);

Send_to to this EP and Receive_from packets from this EP.

3. time_t is defined as follows:

typedef __time64_t time_t;     /* Time value */typedef __int64 __time64_t; /* 64-bit Time value */

That is to say, this time_t is actually a 64bit int, we can use uint64_t this type to swap with, he can use to represent a timestamp.

4. There are two ways to get the last 8 bytes of content, one is to copy pbytes memory directly, one is to construct the Ntppacket, and then take the member, here the latter is easy to understand.

5. Problem with byte order

Network byte order is the big-endian mode, need to be converted, because only need the last uint64_t so I wrote a byte-order conversion function for 64bit:

static void reversebyteorder (uint64_t  &in)  {    uint64_t rs = 0;    int len  = sizeof (uint64_t);    for  (int i = 0; i <  len; i++)  {        std::memset (reinterpret_cast< Uint8_t*> (&RS)  + len - 1 - i                     , static_cast<uint8_t >  ((in & 0xffll <<  (i * 8))  >> i * 8 )                      , 1);     }    in = rs;} 

The high 32 bits of the last 64bit content are stored in UTC seconds, so it needs to be removed and converted to the number of seconds in the local time zone.

Seconds = (last & 0x7fffffff00000000) >> 32;

Note that the highest bit is not available, although it is unsigned, as to why 61533950 this is the author on their own computer to try to find a lot of information is not

Know what is the problem, but also ask everyone to know the reader told me ha.

Then take a look at the main function:

int main (int argc, char* agrv[]) {NtpClient ntp ("129.6.15.28");    int n = 5;        while (n--) {time_t TT = Ntp.gettime ();        Boost::p osix_time::p time UTC = from_time_t (TT); Std::cout << "Local Timestamp:" << time (0) << ' \ t ' << "NTP Server:" << tt << "(" <& Lt        To_simple_string (UTC) << ")" << Std::endl;    Sleep (10); } return 0;}

This makes 5 NTP requests and uses boost to_simple_string to convert UTC time to print results.

This is probably the effect:

Closure

Synchronization time is generally expected to find an HTTP API interface, this article is mainly using the NTP protocol. To cross-platform, the above code avoids using the platform-related macros and functions as much as possible, as long as modifications can be performed on a variety of platforms, as well as the convenience of the robust quasi-standard library of boost for developers.

C + + uses boost to implement network time Protocol (NTP) clients

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.