Вопрос по c – Как написать клиент NTP? [закрыто]

2

Я ищу пример кода записи клиента NTP на C. Я нашелэтот: Fixed some things on code,and it's able to compile. But after "sending data.." it don't nothing. I have no idea how to fix this. Where is problem into code or server? Thanks in advance.

/*
 * This code will query a ntp server for the local time and display
 * it.  it is intended to show how to use a NTP server as a time
 * source for a simple network connected device.
 * This is the C version.  The orignal was in Perl
 *
 * For better clock management see the offical NTP info at:
 * http://www.eecis.udel.edu/~ntp/
 *
 * written by Tim Hogard ([email protected])
 * Thu Sep 26 13:35:41 EAST 2002
 * Converted to C Fri Feb 21 21:42:49 EAST 2003
 * this code is in the public domain.
 * it can be found here http://www.abnormal.com/~thogard/ntp/
 *
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <string.h>

void ntpdate();

int main() {
    ntpdate();
    return 0;
}

void ntpdate() {
char    *hostname="tick.usno.navy.mil";
int portno=123;     //NTP is port 123
int maxlen=1024;        //check our buffers
int i;          // misc var i
unsigned char msg[48]={010,0,0,0,0,0,0,0,0};    // the packet we send
unsigned long  buf[maxlen]; // the buffer we get back
//struct in_addr ipaddr;        //  
struct protoent *proto;     //
struct sockaddr_in server_addr;
int s;  // socket
int tmit;   // the time -- This is a time_t sort of

//use Socket;
//
//#we use the system call to open a UDP socket
//socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";
proto=getprotobyname("udp");
s=socket(PF_INET, SOCK_DGRAM, proto->p_proto);
if(s) {
    perror("asd");
    printf("socket=%d\n",s);
}
//
//#convert hostname to ipaddress if needed
//$ipaddr   = inet_aton($HOSTNAME);
memset( &server_addr, 0, sizeof( server_addr ));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr = inet_addr(hostname);
//argv[1] );
//i   = inet_aton(hostname,&server_addr.sin_addr);
server_addr.sin_port=htons(portno);
//printf("ipaddr (in hex): %x\n",server_addr.sin_addr);

/*
 * build a message.  Our message is all zeros except for a one in the
 * protocol version field
 * msg[] in binary is 00 001 000 00000000 
 * it should be a total of 48 bytes long
*/

// send the data
printf("sending data..\n");
i=sendto(s,msg,sizeof(msg),0,(struct sockaddr *)&server_addr,sizeof(server_addr));

// get the data back
i=recv(s,buf,sizeof(buf),0);
printf("recvfr: %d\n",i);
//perror("recvfr:");

//We get 12 long words back in Network order
/*
for(i=0;i<12;i++)
    printf("%d\t%-8x\n",i,ntohl(buf[i]));
*/

/*
 * The high word of transmit time is the 10th word we get back
 * tmit is the time in seconds not accounting for network delays which
 * should be way less than a second if this is a local NTP server
 */

tmit=ntohl((time_t)buf[10]);    //# get transmit time
//printf("tmit=%d\n",tmit);

/*
 * Convert time to unix standard time NTP is number of seconds since 0000
 * UT on 1 January 1900 unix time is seconds since 0000 UT on 1 January
 * 1970 There has been a trend to add a 2 leap seconds every 3 years.
 * Leap seconds are only an issue the last second of the month in June and
 * December if you don't try to set the clock then it can be ignored but
 * this is importaint to people who coordinate times with GPS clock sources.
 */

tmit-= 2208988800U; 
//printf("tmit=%d\n",tmit);
/* use unix library function to show me the local time (it takes care
 * of timezone issues for both north and south of the equator and places
 * that do Summer time/ Daylight savings time.
 */


//#compare to system time
printf("Time: %s",ctime(&tmit));
i=time(0);
//printf("%d-%d=%d\n",i,tmit,i-tmit);
printf("System time is %d seconds off\n",i-tmit);
}

Ваш Ответ

5   ответов
0


Он протестирован на сервере 2003, VS 2008. Это код, эквивалентный Windows для Unix, который вы предоставили.

#include <stdio.h>
//#include <sys/types.h>
//#include <sys/socket.h>
//#include <netinet/in.h>
//#include <arpa/inet.h>
//#include <netdb.h>
#include <time.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <tchar.h>

#pragma comment(lib, "Ws2_32.lib")

void ntpdate();

int main() {
    ntpdate();
    return 0;
}

void ntpdate() {
char    *hostname="64.27.26.1";//"tick.usno.navy.mil";
int portno=123;     //NTP is port 123
int maxlen=1024;        //check our buffers
long i;          // misc var i
char msg[48]={010,0,0,0,0,0,0,0,0};    // the packet we send
char  *buf = new char[1024]; // the buffer we get back
//struct in_addr ipaddr;        //  
struct protoent *proto;     //
struct sockaddr_in server_addr;
SOCKET s;  // socket
time_t tmit;   // the time -- This is a time_t sort of


//=====================================================================================
//THIS IS WHAT IS MISSING MAJORILY  
//=====================================================================================
        //Initialise the winsock stack
        WSADATA wsaData;
        BYTE wsMajorVersion = 1;
        BYTE wsMinorVersion = 1;
        WORD wVersionRequested = MAKEWORD(wsMinorVersion, wsMajorVersion);   
        if (WSAStartup(wVersionRequested, &wsaData) != 0) 
        {
            _tprintf(_T("Failed to load winsock stack\n"));
            WSACleanup();
            return;
        }
        if (LOBYTE(wsaData.wVersion) != wsMajorVersion || HIBYTE(wsaData.wVersion) != wsMinorVersion)
        {
            _tprintf(_T("Winsock stack does not support version which this program requires\n"));
            WSACleanup();
            return;
        }
//=====================================================================================



//use Socket;
//
//#we use the system call to open a UDP socket
//socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";
proto=getprotobyname("udp");
int err = GetLastError();
s=socket(PF_INET, SOCK_DGRAM, proto->p_proto);
if(s) {
    perror("asd");
    printf("socket=%d\n",s);
}
//
//#convert hostname to ipaddress if needed
//$ipaddr   = inet_aton($HOSTNAME);
memset( &server_addr, 0, sizeof( server_addr ));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr = inet_addr(hostname);
//argv[1] );
//i   = inet_aton(hostname,&server_addr.sin_addr);
server_addr.sin_port=htons(portno);
//printf("ipaddr (in hex): %x\n",server_addr.sin_addr);

/*
 * build a message.  Our message is all zeros except for a one in the
 * protocol version field
 * msg[] in binary is 00 001 000 00000000 
 * it should be a total of 48 bytes long
*/

// send the data
printf("sending data..\n");
i=sendto(s,msg,sizeof(msg),0,(struct sockaddr *)&server_addr,sizeof(server_addr));

int iResult = -1;
    // Receive until the peer closes the connection
    //do {

        iResult = recv(s, buf, 1024, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iRes,ult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());

    //} while( iResult > 0 );

/*
 * The high word of transmit time is the 10th word we get back
 * tmit is the time in seconds not accounting for network delays which
 * should be way less than a second if this is a local NTP server
 */

tmit=ntohl((time_t)buf[10]);    //# get transmit time
//printf("tmit=%d\n",tmit);

/*
 * Convert time to unix standard time NTP is number of seconds since 0000
 * UT on 1 January 1900 unix time is seconds since 0000 UT on 1 January
 * 1970 There has been a trend to add a 2 leap seconds every 3 years.
 * Leap seconds are only an issue the last second of the month in June and
 * December if you don't try to set the clock then it can be ignored but
 * this is importaint to people who coordinate times with GPS clock sources.
 */

tmit -= 2208988800U; 
//printf("tmit=%d\n",tmit);
/* use unix library function to show me the local time (it takes care
 * of timezone issues for both north and south of the equator and places
 * that do Summer time/ Daylight savings time.
 */


//#compare to system time
printf("Time: %s",ctime(&tmit));
i=time(0);
//printf("%d-%d=%d\n",i,tmit,i-tmit);
printf("System time is %d seconds off\n",i-tmit);
}
0

recvfrom() Функция из libc POSIX на любой POSIX-совместимой системе, как Unix-подобные. Или включительно Windows. Так как он поддерживает некоторые основные функции POSIX.

Прочтите руководство по использованию UDP-сокетов, не ориентированных на соединения. они какие-то особенные.

хорошего дня. и надеюсь, что мой пост поможет вам.

веселит;

Авель.

Другое дело, что вы вызываете inet_addr () с именем хоста. Вы должны сначала разрешить этот хост, или просто использовать IP-адрес.
Также вам следует изменить сервер ntp, который вы запрашиваете. так как это, кажется, не работает. попробуйте us.pool.ntp.org
3

Чтобы проверить это, вы можете добавить

printf("receiving data..\n");

до звонка вrecv().

Так жеrecv() звонок может заблокировать.

Это ждетsizeof(buf) байты, которые1024* sizeof(long).

Из комментариев в источнике мы узнаем, что ожидается 12 длинных слов, так что вы можете рассмотреть возможностьrecv() это путем изменения вызова наrecv() вот так:

i = recv(s, buf, 12*sizeof(buf[0]), 0);

Несмотря на все это, я настоятельно рекомендую добавить проверку системных ошибок, напримерsendo() а такжеrecv() также есть. Чтобы сделать это для этих двух, проверьте значение, которое они возвращают, чтобы быть меньше 0, и сделайте некоторую обработку ошибок, если это так.

Для других системных вызовов другие значения могут указывать на ошибку. Увидетьman <method name> для деталей.

@ Джек Вы можете проверить значениеerrno и / или позвонитьperror() Подробнее о том, почему системный вызов (здесь:sendto()) не удалось.
Благодарю. Я решил эту проблему. Ноrecv(s, buf, 48, 0); все еще блокирует. Jack
Теперь я вижу, чтоi=send(s, msg, 48, 0); перестраивается-1. Jack
я изменилсяrecv() размер и добавилprintf() отладить его, как вы упомянули, и этоrecv() функция, которая блокирует. Я тоже пробовал что дано48: sizeof(buf)/ sizeof(buf[0]), Но это дало такую же «ошибку». Jack
3

неверная отметка времени - прочитайте сообщение Android на этой странице, сделанное мной).

Спасибо, что поделился.

 /* This code will query a ntp server for the local time and display

 * it.  it is intended to show how to use a NTP server as a time
 * source for a simple network connected device.
 * This is the C version.  The orignal was in Perl
 *
 * For better clock management see the offical NTP info at:
 * http://www.eecis.udel.edu/~ntp/
 *
 * written by Tim Hogard ([email protected])
 * Thu Sep 26 13:35:41 EAST 2002
 * Converted to C Fri Feb 21 21:42:49 EAST 2003
 * this code is in the public domain.
 * it can be found here http://www.abnormal.com/~thogard/ntp/
 *
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <string.h>

void ntpdate();

int main() {
    ntpdate();
    return 0;
}

void ntpdate() {
char *hostname="163.117.202.33";
int portno=123;     //NTP is port 123
int maxlen=1024;        //check our buffers
int i;          // misc var i
unsigned char msg[48]={010,0,0,0,0,0,0,0,0};    // the packet we send
unsigned long  buf[maxlen]; // the buffer we get back
//struct in_addr ipaddr;        //  
struct protoent *proto;     //
struct sockaddr_in server_addr;
int s;  // socket
int tmit;   // the time -- This is a time_t sort of

//use Socket;
//
//#we use the system call to open a UDP socket
//socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";
proto=getprotobyname("udp");
s=socket(PF_INET, SOCK_DGRAM, proto->p_proto);
perror("socket");
//
//#convert hostname to ipaddress if needed
//$ipaddr   = inet_aton($HOSTNAME);
memset( &server_addr, 0, sizeof( server_addr ));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr = inet_addr(hostname);
//argv[1] );
//i   = inet_aton(hostname,&server_addr.sin_addr);
server_addr.sin_port=htons(portno);
//printf("ipaddr (in hex): %x\n",server_addr.sin_addr);

/*
 * build a message.  Our message is all zeros except for a one in the
 * protocol version field
 * msg[] in binary is 00 001 000 00000000 
 * it should be a total of 48 bytes long
*/

// send the data
printf("sending data..\n");
i=sendto(s,msg,sizeof(msg),0,(struct sockaddr *)&server_addr,sizeof(server_addr));
perror("sendto");
// get the data back
struct sockaddr saddr;
socklen_t saddr_l = sizeof (saddr);
i=recvfrom(s,buf,48,0,&saddr,&saddr_l);
perror("recvfr:");

//We get 12 long words back in Network order
/*
for(i=0;i<12;i++)
    printf("%d\t%-8x\n",i,ntohl(buf[i]));
*/

/*
 * The high word of transmit time is the 10th word we get back
 * tmit is the time in seconds not accounting for network delays which
 * should be way less than a second if this is a local NTP server
 */

tmit=ntohl((time_t)buf[10]);    //# get transmit time
//printf("tmit=%d\n",tmit);

/*
 * Convert time to unix standard time NTP is number of seconds since 0000
 * UT on 1 January 1900 unix time is seconds since 0000 UT on 1 January
 * 1970 There has been a trend to add a 2 leap seconds every 3 years.
 * Leap seconds are only an issue the last second of the month in June and
 * December if you don't try to set the clock then it can be ignored but
 * this is importaint to people who coordinate times with GPS clock sources.
 */

tmit-= 2208988800U; 
//printf("tmit=%d\n",tmit);
/* use unix library function to show me the local time (it takes care
 * of timezone issues for both north and south of the equator and places
 * that do Summer time/ Daylight savings time.
 */


//#compare to system time
printf("Time: %s",ctime(&tmit));
i=time(0);
//printf("%d-%d=%d\n",i,tmit,i-tmit);
printf("System time is %d seconds off\n",i-tmit);
}

И вот вывод:

$ ./sntp_client 
socket: Success
sending data..
sendto: Success
recvfr:: Success
Time: Sun Sep 26 16:00:32 4213
System time is -702316565 seconds off
Взамен получаю плохую дату. Время: понедельник, 1 января, 00:00:00, 19:00. (поменяли сервер и тот же ответ). любая идея?
вот 12 слов, которые я получаю: 0 c0101ed 1 1e 2 d625f93c 3 0 4 d625f94b 5 d625f94b 6 0 7 0 8 0 9 0 10 0 11 0 десятое - 0, поэтому я получаю 1/1/1900 НО, но другие слова представляют правильная дата, в частности 2-е, 4-е и 5-е слова.
просто посмотрите последний код, который я разместил, андроид. попробуйте заменить методы Android на Linux. ура
спасибо! я просто изменил указатель массива на второе слово. :)
0

который я вчера написал на основе вашего кода.

грации;)

он портирован на android, так что вам придется изменить какую-то функцию, чтобы она работала под linux, и раскомментировать некоторые main (), не так ли?

 /* This code will query a ntp server for the local time and display
 * it.  it is intended to show how to use a NTP server as a time
 * source for a simple network connected device.
 * This is the C version.  The orignal was in Perl
 *
 * For better clock management see the offical NTP info at:
 * http://www.eecis.udel.edu/~ntp/
 *
 * written by Tim Hogard ([email protected])
 * Thu Sep 26 13:35:41 EAST 2002
 * Converted to C Fri Feb 21 21:42:49 EAST 2003
 * this code is in the public domain.
 * it can be found here http://www.abnormal.com/~thogard/ntp/
 *
 * ported to android 4.3 on mar/nov/5 - 2013 by abel.
 * the same day ported to a library for agpsd layer.
 */
/*
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <string.h>
#include <utils/SystemClock.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include <sys/time.h>
#define NTP_MODE_CLIENT 3
#define NTP_VERSION 3
#define TRANSMIT_TIME_OFFSET 40
#define REFERENCE_TIME_OFFSET 16
#define ORIGINATE_TIME_OFFSET 24
#define RECEIVE_TIME_OFFSET 32
#define OFFSET_1900_TO_1970 ((uint64_t)((365 * 70) + 17) * 24 * 60 * 60)
*/
void ntpdate(uint64_t *cachedTime, uint64_t *cachedTimeRef, uint64_t *cacheCertainty);
/*
int main() {
    uint64_t cachedTime, cachedTimeRef, cacheCertainty;
    ntpdate(&cachedTime, &cachedTimeRef, &cacheCertainty);
    printf ("%lld\n, %lld\n, %lld\n", cachedTime, cachedTimeRef, cacheCertainty);
    return 0;
}
*/
double random2 () {
    srandom(time(NULL));
    return random();
}

uint64_t currentTimeMillis(/*long int seconds, long int miliseconds*/) {
    struct timeval te; 
    gettimeofday(&te, NULL); // get current time
    uint64_t millis = (uint64_t) te.tv_sec * 1000 + floor(te.tv_usec / 1000); // caculate milliseconds
//  printf ("millis: %llu\n", millis);
    return millis;
}

uint32_t read32(char* buffer, int offset) {
    char b0 = buffer[offset];
    char b1 = buffer[offset+1];
    char b2 = buffer[offset+2];
    char b3 = buffer[offset+3];

    // convert signed bytes to unsigned values
    uint32_t i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
    uint32_t i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
    uint32_t i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
    uint32_t i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);

    uint32_t v = (i0 << 24) + (i1 << 16) + (i2 << 8) + i3;
    return v;
}

uint64_t readTimeStamp(char *buffer, int offset) {
    uint32_t seconds  = read32(buffer, offset);
    uint32_t fraction = read32(buffer, offset + 4);
    uint64_t v = ((int64_t)seconds - OFFSET_1900_TO_1970) * 1000 + (int64_t) fraction * 1000 / (int64_t) 0x100000000;
//  printf ("%llu\n", v);
    return v;
}


void writeTimeStamp(char* buffer, int offset, long long int time) {
    uint64_t seconds = floor (time / 1000);
    uint64_t milliseconds = time - (uint64_t) seconds * 1000;
    seconds += OFFSET_1900_TO_1970;

    // write seconds in big endian format
    buffer[offset++] = (char)(seconds >> 24);
    buffer[offset++] = (char)(seconds >> 16);
    buffer[offset++] = (char)(seconds >> 8);
    buffer[offset++] = (char)(seconds >> 0);

    uint64_t fraction = round ((uint64_t)milliseconds * 0x100000000 / 1000);
    // write fraction in big endian format
    buffer[offset++] = (char)(fraction >> 24);
    buffer[offset++] = (char)(fraction >> 16);
    buffer[offset++] = (char)(fraction >> 8);
    // low order bits should be random data
    buffer[offset++] = (char)(random2() * 255.0);
}

void ntpdate(uint64_t *cachedTime, uint64_t *cachedTimeRef, uint64_t *cacheCertainty) {
    char hostname[]="81.184.154.182";
    int portno=123;     //NTP is port 123
    int maxlen=48;        //check our buffers
    int i;          // misc var i
    uint64_t requestTime = currentTimeMillis();
    uint64_t requestTicks = android::elapsedRealtime();
    char msg[48];
    memset (msg,0,sizeof(msg));
    msg[0]= NTP_MODE_CLIENT | (NTP_VERSION << 3);
    writeTimeStamp(msg, TRANSMIT_TIME_OFFSET, requestTime);
    char  buf[maxlen]; // the buffer we get back
    struct sockaddr_in server_addr;
    int s;  // socket
    time_t tmit;   // the time -- This is a time_t sort of

    s=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    memset( &server_addr, 0, sizeof( server_addr ));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(hostname);
    server_addr.sin_port=htons(portno);

    i=sendto(s,msg,sizeof(msg),0,(struct sockaddr *)&server_addr,sizeof(server_addr));
    struct sockaddr saddr;
    socklen_t saddr_l = sizeof (saddr);
    i=recvfrom(s,buf,sizeof(buf),0,&saddr,&saddr_l);

    uint64_t responseTicks = android::elapsedRealtime();
    uint64_t responseTime = requestTime + (responseTicks - requestTicks);
    uint64_t originateTime = readTimeStamp(buf, ORIGINATE_TIME_OFFSET);
    uint64_t receiveTime = readTimeStamp(buf, RECEIVE_TIME_OFFSET);
    uint64_t transmitTime = readTimeStamp(buf, TRANSMIT_TIME_OFFSET);
    uint64_t roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
    int32_t clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
    //printf ("%lld + %lld = %ld %ld\n", (receiveTime - originateTime), (transmitTime - responseTime), (receiveTime - originateTime + transmitTime - responseTime)/2, clockOffset);
    uint64_t mNtpTime = responseTime + clockOffset;
    uint64_t mNtpTimeReference = responseTicks;
    uint64_t mRoundTripTime = roundTripTime;
    uint64_t mCachedNtpTime = mNtpTime;
    uint64_t mCachedNtpElapsedRealtime = mNtpTimeReference;
    uint64_t mCachedNtpCertainty = mRoundTripTime / 2;
    *cachedTime     = mCachedNtpTime;
    *cachedTimeRef  = mNtpTimeReference;
    *cacheCertainty = mCachedNtpCertainty;

//  uint64_t now = mNtpTime + android::elapsedRealtime() - mNtpTimeReference;
/*
    printf ("%lld\n", now);
    i=currentTimeMillis();
    printf("System time is %lu miliseconds off\n",i-now);
*/
}

Похожие вопросы