【发布时间】:2017-12-05 10:18:45
【问题描述】:
我根据给定的参考here 设计了一个客户端。
我修改了代码(见下文)以满足这些要求
以毫秒为单位打印时间戳
在无限循环中获取 NTP 时间戳、RTT 等。
定义循环时间(每
x秒获取时间)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#define NTP_TIMESTAMP_DELTA 2208988800ull
#define ENDIAN_SWAP32(data) \
((data >> 24) | /* right shift 3 bytes */ \
((data & 0x00ff0000) >> 8) | /* right shift 1 byte */ \
((data & 0x0000ff00) << 8) | /* left shift 1 byte */ \
((data & 0x000000ff) << 24)) /* left shift 3 bytes */
void error(char *msg) {
perror(msg); // Print the error message to stderr.
exit(0); // Quit the process.
}
int main(int argc, char *argv[]) {
int sockfd, n; // Socket file descriptor and the n return result from
// writing/reading from the socket.
int portno = 123; // NTP UDP port number
int i, z = 0;
struct timeval tv1, tv2;
typedef struct {
unsigned li : 2; // Only two bits. Leap indicator.
unsigned vn : 3; // Only three bits. Version number of the protocol.
unsigned
mode : 3; // Only three bits. Mode. Client will pick mode 3 for client.
uint8_t stratum; // Eight bits. Stratum level of the local clock.
uint8_t poll; // Eight bits. Maximum interval between successive messages.
uint8_t precision; // Eight bits. Precision of the local clock.
uint32_t rootDelay; // 32 bits. Total round trip delay time.
uint32_t
rootDispersion; // 32 bits. Max error aloud from primary clock source.
uint32_t refId; // 32 bits. Reference clock identifier.
uint32_t refTm_s; // 32 bits. Reference time-stamp seconds.
uint32_t refTm_f; // 32 bits. Reference time-stamp fraction of a second.
uint32_t origTm_s; // 32 bits. Originate time-stamp seconds.
uint32_t origTm_f; // 32 bits. Originate time-stamp fraction of a second.
uint32_t rxTm_s; // 32 bits. Received time-stamp seconds.
uint32_t rxTm_f; // 32 bits. Received time-stamp fraction of a second.
uint32_t txTm_s; // 32 bits and the most important field the client cares
// about. Transmit time-stamp seconds.
uint32_t txTm_f; // 32 bits. Transmit time-stamp fraction of a second.
} ntp_packet; // Total: 384 bits or 48 bytes.
// Create and zero out the packet. All 48 bytes worth.
ntp_packet packet = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
memset(&packet, 0, sizeof(ntp_packet));
*((char *)&packet + 0) =
0x1b; // Represents 27 in base 10 or 00011011 in base 2.
uint8_t *ptr = (uint8_t *)(&packet); /* to read raw bytes */
struct sockaddr_in serv_addr; // Server address data structure.
struct hostent *server; // Server data structure.
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Create a UDP socket.
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]); // Convert URL to IP.
if (server == NULL)
error("ERROR, no such host");
// Zero out the server address structure.
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
// Copy the server's IP address to the server address structure.
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
server->h_length);
// Convert the port number integer to network big-endian style and save it to
// the server address structure.
serv_addr.sin_port = htons(portno);
// Call up the server using its IP address and port number.
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("\nNTP client started \n\n");
while (1) {
z = z + 1;
ntp_packet packet = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
memset(&packet, 0, sizeof(ntp_packet));
*((char *)&packet + 0) =
0x1b; // Represents 27 in base 10 or 00011011 in base 2.
uint8_t *ptr = (uint8_t *)(&packet); /* to read raw bytes */
gettimeofday(&tv1, NULL);
unsigned long long millisecondsSinceEpochStart =
(unsigned long long)(tv1.tv_sec) * 1000 +
(unsigned long long)(tv1.tv_usec) / 1000;
n = write(sockfd, (char *)&packet, sizeof(ntp_packet));
if (n < 0)
error("ERROR writing to socket");
n = read(sockfd, (char *)&packet, sizeof(ntp_packet));
if (n < 0)
error("ERROR reading from socket");
gettimeofday(&tv2, NULL);
unsigned long long millisecondsSinceEpochEnd =
(unsigned long long)(tv2.tv_sec) * 1000 +
(unsigned long long)(tv2.tv_usec) / 1000;
packet.precision = ntohl(packet.precision); // Precision
packet.rootDelay = ntohl(packet.rootDelay);
packet.rxTm_s = ntohl(packet.rxTm_s); // Time-stamp seconds.
packet.rxTm_f = ntohl(packet.rxTm_f); // Time-stamp fraction of a second.
packet.txTm_s = ntohl(packet.txTm_s); // Time-stamp seconds.
packet.txTm_f = ntohl(packet.txTm_f); // Time-stamp fraction of a second.
// packet.rootDelay = ntohl(packet.rootDelay); // RTT
// time_t rootDelay = ( time_t ) ( packet.rootDelay - NTP_TIMESTAMP_DELTA );
printf("\n................................................................."
"...\n");
printf("\nIteration Number : %d\n", z);
printf("..................................................................."
"..\n");
printf("NTP Telegram Contains\n");
for (i = 0; i < sizeof(ntp_packet); i++) {
if (i != 0 && i % 8 == 0)
printf("\n");
printf("0x%2x ", ptr[i]);
}
printf("\n\n\n");
printf("Client Send Timestamp T1(ms): %llu\n", millisecondsSinceEpochStart);
printf("server Recieve Timestamp T2: %llu.", packet.rxTm_s);
printf("%llu\n", packet.rxTm_f);
printf("server Transmit Timestamp T3: %llu.", packet.txTm_s);
printf("%llu\n", packet.txTm_f);
printf("Client Recieve Timestamp T4(ms): %llu\n",
millisecondsSinceEpochEnd);
printf("RTT (calculated by NTP): %llu\n", packet.rootDelay);
printf("Precision (calculated by NTP): %llu\n", packet.precision);
sleep(atoi(argv[2]));
}
return 0;
close(sockfd);
}
生成文件:
.PHONY: all clean tags
CFLAGS := -Wall -O2
all: client
client: client.c
$(CC) $(CFLAGS) $^ -o $@
strip -s $@
tags:
ctags -R .
clean:
-rm *.o client
使用
制作并运行代码./client 0.pool.ntp.org 1
我面临的问题,需要您的建议,可能的代码更改和改进
代码不能无限运行,它会在两者之间停止,并且在一些迭代后不打印任何输出(不显示错误消息)
尽管
64位,但时间戳大小不同RTT 和precision 打印相同的值并且不会在每次迭代中更新(有时两者都显示
0)如何从
packet.rxTm_s和packet.rxTm_f构建T2作为64bit 的一个时间戳。
【问题讨论】:
-
您的链接是一个糟糕的教程。
-
我担心没有太多东西可以开始。 :( 如果 yoz 能提供一些建议会很有帮助