我正在寻找用C语言编写NTP客户端的代码示例。我发现this: 修复了代码上的一些问题,并且能够编译。但在“发送数据......”之后,它并没有什么。我不知道如何解决这个问题。代码或服务器的问题在哪里?提前谢谢。
/*
* 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 (thogard@abnormal.com)
* 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);
}
答案 0 :(得分:3)
不确定sendto()是否阻塞。
要测试此功能,您可能需要添加
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>
。
答案 1 :(得分: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 (thogard@abnormal.com)
* 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
答案 2 :(得分:0)
这是由我修改并编译和执行的代码 它在服务器2003,VS 2008上进行了测试。这是您提供的Unix的Windows等效代码
#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", iResult);
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);
}
答案 3 :(得分:0)
你应该在任何POSIX兼容系统上使用来自POSIX libc的recvfrom()
函数,就像Unix一样。或包容性Windows。因为它支持一些基本的POSIX功能。
阅读使用UDP套接字的手册,而不是面向连接。他们有些特别。
祝你有个愉快的一天。 并希望我的帖子可以帮助你。
欢呼声;
阿贝尔。
答案 4 :(得分:0)
这里有一个完整的NTP客户端,我昨天根据你的代码进行了编码。
gracias;)
它被移植到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 (thogard@abnormal.com)
* 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);
*/
}