- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
几个月来,我一直在尝试基于 RFC5905 创建一个简单的 SNTP 单一客户端/服务器.最后我设法让它工作至少我认为它工作正常,但是当我尝试针对真实的 NTP 服务器(例如 0.se.pool.ntp.org:123)测试我的代码时,我收到的时间戳需要重新计算。我已经尝试了几种不同的方法,但现在已经 3 天了,但无论如何我都没有尝试过。
有人知道如何将 NTP 时间戳转换为 Unix 纪元时间戳吗?
执行服务器的语法,例如./server 127.0.0.1:5000 和 Client 例如./client 127.0.0.1:5000
针对真实 NTP 服务器执行客户端的语法,例如./client 0.se.pool.ntp.org:123
客户端工作代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <math.h>
#include <sys/timeb.h>
#include <inttypes.h>
#include <limits.h>
#include <assert.h>
#define UNIX_EPOCH 2208988800UL /* 1970 - 1900 in seconds */
typedef struct client_packet client_packet;
struct client_packet {
uint8_t client_li_vn_mode;
uint8_t client_stratum;
uint8_t client_poll;
uint8_t client_precision;
uint32_t client_root_delay;
uint32_t client_root_dispersion;
uint32_t client_reference_identifier;
uint32_t client_reference_timestamp_sec;
uint32_t client_reference_timestamp_microsec;
uint32_t client_originate_timestamp_sec;
uint32_t client_originate_timestamp_microsec;
uint32_t client_receive_timestamp_sec;
uint32_t client_receive_timestamp_microsec;
uint32_t client_transmit_timestamp_sec;
uint32_t client_transmit_timestamp_microsec;
}__attribute__((packed));
typedef struct server_send server_send;
struct server_send {
uint8_t server_li_vn_mode;
uint8_t server_stratum;
uint8_t server_poll;
uint8_t server_precision;
uint32_t server_root_delay;
uint32_t server_root_dispersion;
char server_reference_identifier[4];
uint32_t server_reference_timestamp_sec;
uint32_t server_reference_timestamp_microsec;
uint32_t server_originate_timestamp_sec;
uint32_t server_originate_timestamp_microsec;
uint32_t server_receive_timestamp_sec;
uint32_t server_receive_timestamp_microsec;
uint32_t server_transmit_timestamp_sec;
uint32_t server_transmit_timestamp_microsec;
}__attribute__((packed));
/* Linux man page bind() */
#define handle_error(msg) \
do {perror(msg); exit(EXIT_FAILURE);} while (0)
uint32_t ClockGetTime() {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (uint32_t)ts.tv_sec * 1000000LL + (uint32_t)ts.tv_nsec / 1000LL;
}
int main(int argc, char *argv[]) {
int sockfd , numbytes;
struct addrinfo hints, *servinfo, *p;
int rv;
client_packet memsend;
server_send memrcv;
memset( &memsend , 0 , sizeof memsend );
memset( &memrcv , 0 , sizeof memrcv );
char IP[16]; /* IP = 15 digits 1 extra for \0 null terminating character string */
char PORT_STR[6]; /* Port = 5 digits MAX 1 extra for \0 null terminating character string */
memset(IP , '\0' , sizeof(IP));
memset(PORT_STR , '\0' , sizeof(PORT_STR));
strcpy(IP, strtok(argv[1], ":"));
strcpy(PORT_STR, strtok(NULL, ":"));
memset( &hints , 0 , sizeof hints );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ( ( rv = getaddrinfo( IP , PORT_STR , &hints , &servinfo ) ) != 0 ) {
fprintf( stderr , "getaddrinfo: %s\n" , gai_strerror(rv) );
return 1;
}
// loop through all the results and make a socket
for( p = servinfo; p != NULL; p = p->ai_next ) {
if ( ( sockfd = socket( p->ai_family , p->ai_socktype , p->ai_protocol ) ) == -1 ) {
handle_error( "socket" );
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Error while binding socket\n");
return 2;
}
memsend.client_li_vn_mode = 0b00100011;
memsend.client_stratum = 0;
memsend.client_poll = 0;
memsend.client_precision = 0;
memsend.client_root_delay = 0;
memsend.client_root_dispersion = 0;
memsend.client_reference_identifier = 0;
memsend.client_reference_timestamp_sec = 0;
memsend.client_reference_timestamp_microsec = 0;
memsend.client_receive_timestamp_sec = 0;
memsend.client_receive_timestamp_microsec = 0;
time_t time_originate_sec = time(NULL);
memsend.client_originate_timestamp_sec = time_originate_sec;
memsend.client_originate_timestamp_microsec = ClockGetTime();
memsend.client_transmit_timestamp_sec = memsend.client_originate_timestamp_sec;
memsend.client_transmit_timestamp_microsec = memsend.client_originate_timestamp_microsec;
if ( ( numbytes = sendto( sockfd, &memsend , sizeof memsend , 0 ,
p->ai_addr , p->ai_addrlen ) ) == -1 ) {
handle_error("sendto");
exit(1);
}
if ( ( numbytes = recvfrom( sockfd , &memrcv , sizeof memrcv , 0 ,
(struct sockaddr *) &p->ai_addr, &p->ai_addrlen ) ) == -1 ) {
handle_error( "recvfrom" );
exit(1);
}
time_t time_rcv_sec = time(NULL);
uint32_t client_rcv_timestamp_sec = time_rcv_sec;
uint32_t client_rcv_timestamp_microsec = ClockGetTime();
freeaddrinfo(servinfo);
char Identifier[5];
memset(Identifier , '\0' , sizeof Identifier);
memcpy(Identifier , memrcv.server_reference_identifier , sizeof memrcv.server_reference_identifier);
printf("\t Reference Identifier \t %"PRIu32" \t\t\t %s\n",memsend.client_reference_identifier,Identifier);
printf("\t Reference Timestamp \t %"PRIu32".%"PRIu32" \t\t\t %"PRIu32".%"PRIu32"\n",memsend.client_reference_timestamp_sec,memsend.client_reference_timestamp_microsec,memrcv.server_reference_timestamp_sec,memrcv.server_reference_timestamp_microsec);
printf("\t Originate Timestamp \t %"PRIu32".%"PRIu32" \t %"PRIu32".%"PRIu32"\n",memsend.client_originate_timestamp_sec,memsend.client_originate_timestamp_microsec,memrcv.server_originate_timestamp_sec,memrcv.server_originate_timestamp_microsec);
printf("\t Receive Timestamp \t %"PRIu32".%"PRIu32" \t %"PRIu32".%"PRIu32"\n",client_rcv_timestamp_sec,client_rcv_timestamp_microsec,memrcv.server_receive_timestamp_sec,memrcv.server_receive_timestamp_microsec);
printf("\t Transmit Timestamp \t %"PRIu32".%"PRIu32" \t %"PRIu32".%"PRIu32"\n\n",memsend.client_transmit_timestamp_sec,memsend.client_transmit_timestamp_microsec,memrcv.server_transmit_timestamp_sec,memrcv.server_transmit_timestamp_microsec);
close(sockfd);
return 0;
}
服务器代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <math.h>
#include <sys/timeb.h>
#include <inttypes.h>
#include <limits.h>
#define TRUE 1
typedef struct client_send client_send;
struct client_send {
uint8_t client_li_vn_mode;
uint8_t client_startum;
uint8_t client_poll;
uint8_t client_precision;
uint32_t client_root_delay;
uint32_t client_root_dispersion;
uint32_t client_reference_identifier;
uint32_t client_reference_timestamp_sec;
uint32_t client_reference_timestamp_microsec;
uint32_t client_originate_timestamp_sec;
uint32_t client_originate_timestamp_microsec;
uint32_t client_receive_timestamp_sec;
uint32_t client_receive_timestamp_microsec;
uint32_t client_transmit_timestamp_sec;
uint32_t client_transmit_timestamp_microsec;
}__attribute__((packed));
typedef struct server_packet server_packet;
struct server_packet {
uint8_t server_li_vn_mode;
uint8_t server_startum;
uint8_t server_poll;
uint8_t server_precision;
uint32_t server_root_delay;
uint32_t server_root_dispersion;
char server_reference_identifier[4];
uint32_t server_reference_timestamp_sec;
uint32_t server_reference_timestamp_microsec;
uint32_t server_originate_timestamp_sec;
uint32_t server_originate_timestamp_microsec;
uint32_t server_receive_timestamp_sec;
uint32_t server_receive_timestamp_microsec;
uint32_t server_transmit_timestamp_sec;
uint32_t server_transmit_timestamp_microsec;
}__attribute__((packed));
/* Linux man page bind() */
#define handle_error(msg) \
do {perror(msg); exit(EXIT_FAILURE);} while (0)
uint32_t ClockGetTime() {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (uint32_t)ts.tv_sec * 1000000LL + (uint32_t)ts.tv_nsec / 1000LL;
}
unsigned long int precision() {
struct timespec res;
if ( clock_getres( CLOCK_REALTIME, &res) == -1 ) {
perror( "clock get resolution" );
return EXIT_FAILURE;
}
return res.tv_nsec / 1000;
}
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[]) {
server_packet send_mem;
client_send rcv_mem;
/* Empty structs */
memset( &send_mem , 0 , sizeof send_mem );
memset( &rcv_mem , 0 , sizeof rcv_mem );
char s[INET_ADDRSTRLEN];
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;
socklen_t addr_len;
int get, numbytes;
int sockfd;
char IP[16];
char PORT_STR[6];
memset(IP , '\0' , sizeof(IP));
memset(PORT_STR , '\0' , sizeof(PORT_STR));
strcpy(IP, strtok(argv[1], ":"));
strcpy(PORT_STR, strtok(NULL, ":"));
memset( &hints , 0 , sizeof hints );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = IPPROTO_UDP;
if ( ( get = getaddrinfo( NULL , PORT_STR , &hints , &servinfo ) ) != 0) {
fprintf( stderr , "getaddrinfo: %s\n" , gai_strerror(get) );
return 1;
}
for( p = servinfo; p != NULL; p = p->ai_next ) {
if ( ( sockfd = socket( p->ai_family , p->ai_socktype ,
p->ai_protocol ) ) == -1 ) {
handle_error("socket");
continue;
}
if ( bind( sockfd , p->ai_addr , p->ai_addrlen ) == -1 ) {
close(sockfd);
handle_error("bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Not able to bind socket\n");
return 2;
}
freeaddrinfo(servinfo);
printf("\nServer is up and running: waiting to recv msg at port: %s...\n",
PORT_STR);
while(TRUE) {
time_t t_ref_sec = time(NULL);
unsigned long int Ref_epoc_sec = t_ref_sec;
send_mem.server_reference_timestamp_sec = Ref_epoc_sec;
unsigned long int t_ref_nanosec = ClockGetTime();
send_mem.server_reference_timestamp_microsec = t_ref_nanosec;
addr_len = sizeof(their_addr);
if ((numbytes = recvfrom(sockfd, &rcv_mem , sizeof rcv_mem , 0,
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
handle_error("recvfrom");
exit(1);
}
time_t t_rcv_sec = time(NULL);
send_mem.server_receive_timestamp_sec = t_rcv_sec;
send_mem.server_receive_timestamp_microsec = ClockGetTime();
printf("Peer address: %s\n",
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof(s)));
printf("Peer port: %i\n",p->ai_socktype);
send_mem.server_li_vn_mode = 0b00100100;
send_mem.server_startum = 0b00000001;
send_mem.server_poll = 0b00000110;
send_mem.server_precision = precision();
send_mem.server_root_delay = 0;
send_mem.server_root_dispersion = 0;
memcpy( send_mem.server_reference_identifier , "LOCL" ,
sizeof send_mem.server_reference_identifier );
send_mem.server_originate_timestamp_sec = rcv_mem.client_originate_timestamp_sec;
send_mem.server_originate_timestamp_microsec = rcv_mem.client_originate_timestamp_microsec;
time_t t_send_sec = time(NULL);
send_mem.server_transmit_timestamp_sec = t_send_sec;
send_mem.server_transmit_timestamp_microsec = ClockGetTime();
if ( sendto( sockfd, &send_mem , sizeof send_mem , 0 ,
(struct sockaddr *) &their_addr , addr_len ) == -1 ) {
handle_error("sendto");
exit(1);
}
}
close(sockfd);
return 0;
}
我使用服务器和客户端时的打印输出示例。
Reference Identifier 0 LOCL
Reference Timestamp 0.0 1426637081.3564398733
Originate Timestamp 1426637087.3570333925 1426637087.3570333925
Receive Timestamp 1426637087.3570334078 1426637087.3570334003
Transmit Timestamp 1426637087.3570333925 1426637087.3570334046
当我探测一个真实的 NTP 服务器(例如 0.se.pool.ntp.org:123)时的打印输出示例。
Reference Identifier 0 �$�
Reference Timestamp 0.0 3879449560.3503094062
Originate Timestamp 1426637090.3573978972 1426637090.3573978972
Receive Timestamp 1426637090.3573992772 2722083800.781009125
Transmit Timestamp 1426637090.3573978972 2722083800.937312997
预期的输出类似于我之前发布的打印输出。
预先感谢大家花时间和精力帮助我。
更新 相关问题但与我要找的答案不相近How to write a NTP client? [closed] .
最佳答案
将NTP时间戳转换为Unix时间戳(struct timeval)涉及两个需要解决的问题。
一个是两个纪元之间的偏移量。 Unix 使用位于 1/1/1970-00:00h (UTC) 的纪元,NTP 使用 1/1/1900-00:00h。这导致偏移量相当于以秒为单位的 70 年(两个日期之间有 17 个闰年,因此偏移量为
(70*365 + 17)*86400 = 2208988800
从 NTP 时间中减去以获得 Unix struct timeval
。
第二个是 struct timeval
使用 1/1000000 sec
作为亚秒分数的单位,NTP 使用 1/2^32 sec
作为它的小数时间单位。要从 NTP 转换为 struct timeval
,可以将小数部分除以 2^32
(这很简单,它是右移),然后乘以 1000000
。为了解决这个问题,我们必须使用 64 位算法,因为数字介于 0
和 2^32
之间,所以最好的是:
从 NTP 转换为 struct timeval
将小数部分字段(NTP 时间戳的右 32 位)复制到 uint64_t
变量并将其乘以1000000
,然后将其右移 32 位位置以获得正确的值。您必须考虑到 NTP 时间戳是按网络字节顺序排列的,因此您可能必须进行一些调整才能使用这些数字。
要从 struct timeval
进行转换,将 unix 时间的 tv_usec
字段复制到 uint64_t
并将其左移 32 位位置, 然后除以 1000000
并转换为网络字节顺序(最重要的字节在前)
以下代码示例说明了这一点。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <getopt.h>
#define OFFSET 2208988800ULL
void ntp2tv(uint8_t ntp[8], struct timeval *tv)
{
uint64_t aux = 0;
uint8_t *p = ntp;
int i;
/* we get the ntp in network byte order, so we must
* convert it to host byte order. */
for (i = 0; i < sizeof ntp / 2; i++) {
aux <<= 8;
aux |= *p++;
} /* for */
/* now we have in aux the NTP seconds offset */
aux -= OFFSET;
tv->tv_sec = aux;
/* let's go with the fraction of second */
aux = 0;
for (; i < sizeof ntp; i++) {
aux <<= 8;
aux |= *p++;
} /* for */
/* now we have in aux the NTP fraction (0..2^32-1) */
aux *= 1000000; /* multiply by 1e6 */
aux >>= 32; /* and divide by 2^32 */
tv->tv_usec = aux;
} /* ntp2tv */
void tv2ntp(struct timeval *tv, uint8_t ntp[8])
{
uint64_t aux = 0;
uint8_t *p = ntp + sizeof ntp;
int i;
aux = tv->tv_usec;
aux <<= 32;
aux /= 1000000;
/* we set the ntp in network byte order */
for (i = 0; i < sizeof ntp/2; i++) {
*--p = aux & 0xff;
aux >>= 8;
} /* for */
aux = tv->tv_sec;
aux += OFFSET;
/* let's go with the fraction of second */
for (; i < sizeof ntp; i++) {
*--p = aux & 0xff;
aux >>= 8;
} /* for */
} /* ntp2tv */
size_t print_tv(struct timeval *t)
{
return printf("%ld.%06ld\n", t->tv_sec, t->tv_usec);
}
size_t print_ntp(uint8_t ntp[8])
{
int i;
int res = 0;
for (i = 0; i < sizeof ntp; i++) {
if (i == sizeof ntp / 2)
res += printf(".");
res += printf("%02x", ntp[i]);
} /* for */
res += printf("\n");
return res;
} /* print_ntp */
int main(int argc, char *argv[])
{
struct timeval t;
uint8_t ntp[8];
gettimeofday(&t, NULL);
printf("tv2ntp\n");
tv2ntp(&t, ntp);
printf("tv : "); print_tv(&t);
printf("ntp: "); print_ntp(ntp);
printf("ntp2tv\n");
ntp2tv(ntp, &t);
printf("tv : "); print_tv(&t);
printf("ntp: "); print_ntp(ntp);
}
关于c - C语言(Linux)如何将NTP时间转换为Unix Epoch时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29112071/
您好,我是使用 xampp 的 PHPmyadmin 新手,没有 MYSQL 背景。当我喜欢研究它是如何工作的时,我的脑海中浮现出一个想法,它让我一周都无法休眠,因为我似乎无法弄清楚如何使用 MIN(
Go docs say (强调): Programs using times should typically store and pass them as values, not pointers.
我有一组用户在 8 月 1 日有一个条目。我想找到在 8 月 1 日有条目但在 8 月 2 日没有做任何事情的用户。 现在是 10 月,所以事件已经过去很久了。 我有限的知识说: SELECT * F
我有以下代码,主要编码和取消编码时间结构。这是代码 package main import ( "fmt" "time" "encoding/json" ) type chec
您能详细解释一下“用户 CPU 时间”和“系统 CPU 时间”吗?我读了很多,但我不太理解。 最佳答案 区别在于时间花在用户空间还是内核空间。用户 CPU 时间是处理器运行程序代码(或库中的代码)所花
应用程序不计算东西,但做输入/输出、读取文件、使用网络。我希望探查器显示它。 我希望像 callgrind 中的东西一样,在每个问题中调用 clock_gettime。 或者像 oprofile 那样
目前我的 web 应用程序接收 websocket 数据来触发操作。 这会在页面重新加载时中断,因此我需要一个能够触发特定事件的客户端解决方案。 这个想法可行吗? 假设你有 TimeX = curre
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我有一个 Instant (org.joda.time.Instant) 的实例,我在一些 api 响应中得到它。我有另一个来自 (java.time.Instant) 的实例,这是我从其他调用中获得
如何集成功能 f(y) w.r.t 时间;即 'y'是一个包含 3000 个值和值 time(t) 的数组从 1 到 3000 不等。所以,在整合 f(y) 后我需要 3000 个值. 积分将是不确定
可以通过 CLI 创建命名空间,但是如何使用 Java SDK 来创建命名空间? 最佳答案 它以编程方式通过 gRPC API 完成由服务公开。 在 Java 中,生成的 gRPC 客户端可以通过 W
我有一个函数,它接受 2 组日期(开始日期和结束日期),这些日期将用于我的匹配引擎 我必须知道start_date1和end_date1是否在start_date2和end_date2内 快进:当我在
我想从 Python 脚本运行“time”unix 命令,以计算非 Python 应用程序的执行时间。我会使用 os.system 方法。有什么方法可以在Python中保存这个输出吗?我的目标是多次运
我正在寻找一种“漂亮的数字”算法来确定日期/时间值轴上的标签。我熟悉 Paul Heckbert's Nice Numbers algorithm . 我有一个在 X 轴上显示时间/日期的图,用户可以
在 PowerShell 中,您可以格式化日期以返回当前小时,如下所示: Get-Date -UFormat %H 您可以像这样在 UTC 中获取日期字符串: $dateNow = Get-Date
我正在尝试使用 Javascript 向父子窗口添加一些页面加载检查功能。 我的目标是“从父窗口”检测,每次子窗口完全加载然后执行一些代码。 我在父窗口中使用以下代码示例: childPage=wi
我正在尝试设置此 FFmpeg 命令的 drawtext 何时开始,我尝试使用 start_number 但看起来它不会成功。 ffmpeg -i 1.mp4 -acodec aac -keyint_
我收到了一个 Excel (2010) 电子表格,它基本上是一个文本转储。 单元格 - J8 具有以下信息 2014 年 2 月 4 日星期二 00:08:06 EST 单元格 - L8 具有以下信息
我收到的原始数据包含一列具有以下日期和时间戳格式的数据: 2014 年 3 月 31 日凌晨 3:38 单元格的格式并不一致,因为有些单元格有单个空格,而另一些单元格中有两个或三个字符之间的空格。所以
我想知道是否有办法在我的 Grails 应用程序顶部显示版本和构建日期。 编辑:我应该说我正在寻找构建应用程序的日期/时间。 最佳答案 在您的主模板中,或任何地方。 Server version:
我是一名优秀的程序员,十分优秀!