如何从NTP服务器接收数据?

时间:2016-05-29 18:29:38

标签: c++ ntp

我不知道为什么发送数据是48字节010,0,0 ......,有人可以解释一下吗?问题是收到数据的缓冲,我不知道他应该有多大,即使我收到数据,如何从中获得正常时间?

以下是代码:

#include <iostream>

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_MEAN_AND_LEAN

#include <winsock2.h>
#include <windows.h>

#include <time.h>



using namespace std;

class HRException
{
public:
    HRException() :
        m_pMessage("") {}
    virtual ~HRException() {}
    HRException(const char *pMessage) :
        m_pMessage(pMessage) {}
    const char * what() { return m_pMessage; }
private:
    const char *m_pMessage;
};

const int  REQ_WINSOCK_VER = 2; // Minimum winsock version required
const char DEF_SERVER_NAME[] = "0.pl.pool.ntp.org";
const int  SERVER_PORT = 123;
const int  TEMP_BUFFER_SIZE = 128;

const char msg[48] = { 010,0,0,0,0,0,0,0,0 };


// IP number typedef for IPv4
typedef unsigned long IPNumber;

IPNumber FindHostIP(const char *pServerName)
{
    HOSTENT *pHostent;

    // Get hostent structure for hostname:
    if (!(pHostent = gethostbyname(pServerName)))
        throw HRException("could not resolve hostname.");

    // Extract primary IP address from hostent structure:
    if (pHostent->h_addr_list && pHostent->h_addr_list[0])
        return *reinterpret_cast<IPNumber*>(pHostent->h_addr_list[0]);

    return 0;
}

void FillSockAddr(sockaddr_in *pSockAddr, const char *pServerName, int portNumber)
{
    // Set family, port and find IP
    pSockAddr->sin_family = AF_INET;
    pSockAddr->sin_port = htons(portNumber);
    pSockAddr->sin_addr.S_un.S_addr = FindHostIP(pServerName);
}

bool RequestHeaders(const char *pServername)
{
    SOCKET      hSocket = INVALID_SOCKET;
    char        tempBuffer[TEMP_BUFFER_SIZE];
    sockaddr_in sockAddr = { 0 };
    bool        bSuccess = true;

    try
    {
        // Lookup hostname and fill sockaddr_in structure:
        cout << "Looking up hostname " << pServername << "... ";
        FillSockAddr(&sockAddr, pServername, SERVER_PORT);
        cout << "found.\n";

        // Create socket
        cout << "Creating socket... ";
        if ((hSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
            throw HRException("could not create socket.");
        cout << "created.\n";

        // Connect to server
        cout << "Attempting to connect to " << inet_ntoa(sockAddr.sin_addr)
            << ":" << SERVER_PORT << "... ";
        if (connect(hSocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) != 0)
            throw HRException("could not connect.");
        cout << "connected.\n";

        cout << "Sending request... ";

        // send request part 1
        if (send(hSocket, msg, sizeof(msg) , 0) == SOCKET_ERROR)
            throw HRException("failed to send data.");



        cout << "request sent.\n";

        cout << "Dumping received data...\n\n";
        // Loop to print all data

        recv(hSocket, tempBuffer, sizeof(tempBuffer), 0);  // <-- the problem
    ///
       //part where we take time out of tempBuffer

    ///







    }
    catch (HRException e)
    {
        cerr << "\nError: " << e.what() << endl;
        bSuccess = false;
    }

    if (hSocket != INVALID_SOCKET)
    {
        closesocket(hSocket);
    }
    return bSuccess;
}

int main(int argc, char* argv[])
{

    int iRet = 1;
    WSADATA wsaData;

    cout << "Initializing winsock... ";

    if (WSAStartup(MAKEWORD(REQ_WINSOCK_VER, 0), &wsaData) == 0)
    {
        // Check if major version is at least REQ_WINSOCK_VER
        if (LOBYTE(wsaData.wVersion) >= REQ_WINSOCK_VER)
        {
            cout << "initialized.\n";

            // Set default hostname:
            const char *pHostname = DEF_SERVER_NAME;

            // Set custom hostname if given on the commandline:
            if (argc > 1)
                pHostname = argv[1];

            iRet = !RequestHeaders(pHostname);
        }
        else
        {
            cerr << "required version not supported!";
        }

        cout << "Cleaning up winsock... ";

        // Cleanup winsock
        if (WSACleanup() != 0)
        {
            cerr << "cleanup failed!\n";
            iRet = 1;
        }
        cout << "done.\n";
    }
    else
    {
        cerr << "startup failed!\n";
    }
    int x;
    cin >> x;

    return iRet;
}

代码的大部分内容来自madwizard.org

2 个答案:

答案 0 :(得分:0)

确定它有效,代码的主要部分:

        const char msg[48] = { 010,0,0,0,0,0,0,0,0 };

        if (send(hSocket, msg, sizeof(msg) , 0) == SOCKET_ERROR)
            throw HRException("failed to send data.");



        cout << "request sent.\n";

        cout << "Dumping received data...\n\n";


        char   tempBuffer[1024];
        int bytes =  recv(hSocket, tempBuffer, sizeof(tempBuffer), 0);  
        cout << "bytes received: " << bytes << endl;

        time_t tmit;
        tmit = ntohl(((time_t*)tempBuffer)[4]);
        tmit -= 2208988800U;

        cout << ctime(&tmit);

不知道为什么我们发送的数据是

msg[48] = { 010,0,0,0,0,0,0,0,0 };

为什么收到的数据包含很多数字?例如,如果将代码更改为

tmit = ntohl(((time_t*)tempBuffer)[6]);

我会得到2008y日期,为什么?

为什么这么多的弊端?还在等待解释:D

这里的整个代码http://pastebin.com/Sv3ERGfV,别忘了链接ws2_32.lib

答案 1 :(得分:0)

my issue类似,尝试查询来自self-hostet Windows-NTP-Server的C ++库NTPClient的时间,该库使用boost来执行网络任务,msg[48] = { 010,0,0,0,0,0,0,0,0 };配置 ntp.flags.mode 。使用Wireshark比较w32tm /stripchart /computer:10.159.96.65的网络流量后,标志27或11似乎是我的用例的选择: Comparison of NTP network packages

tmit = ntohl(((time_t*)tempBuffer)[6]);从收到的包中提取数据。它看起来像

  • 4产生参考时间(我假设的最后一次与时间服务器同步),
  • 8服务器收到请求的时间和
  • 10发送时间(应该几乎相等)。