WT与RTC

网上自行搜索了解两者区别:

  • 系统时间(WT, Wall Time):由Linux系统软件维持的时间。

  • RTC(Real-Time Clock):翻译过来是实时时钟芯片。

对于一台安装了操作系统的服务器来说,操作系统和服务器硬件本身都在记录和更新当前的时间,也就是说系统时间和RTC时间是两套独立的计时机制。简单的说就是——RTC时间才是真正持续更新,而操作系统则是只有在系统启动以后才会持续更新,在操作系统关闭或重启期间,甚至服务器下电期间,整个服务器的时间就依赖于RTC了。

NTP服务器列表

域名 IP地址
time-a.nist.gov 129.6.15.28
time-b.nist.gov 129.6.15.29
time-a.timefreq.bldrdoc.gov 132.163.4.101
time-b.timefreq.bldrdoc 132.163.4.102
time-c.timefreq.bldrdoc.gov 132.163.4.103
utcnist.colorado.edu 128.138.140.44
time.nist.gov 192.43.244.18
time-nw.nist.gov 131.107.1.10
nist1.datum.com 66.243.43.21
nist1-dc.glassey.com 216.200.93.8
nist1-ny.glassey.com 208.184.49.9
nist1-sj.glassey.com 207.126.98.204
nist1.aol-ca.truetime.com 207.200.81.113
nist1.aol-va.truetime.com 205.188.185.33
国家授时 210.72.145.44

ntppool提供了各个地区的NTP池,我测试了几个,发现巴西的https://www.pool.ntp.org/zone/br (200.20.186.76)比较好用。

代码实现如下:

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <iostream>

#define LOG(...)                                               \
  {                                                            \
    fprintf(stderr, "{{%s: Line %d:}}\t", __FILE__, __LINE__); \
    fprintf(stderr, __VA_ARGS__);                              \
    fprintf(stderr, "\n");                                     \
  }

void ntpdate();

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

void ntpdate() {
  char *hostname = (char *)"200.20.186.76";               // pool.ntp.br NTP server IP
  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
  long tmit;  // the time -- This is a time_t sort of

  LOG("200.20.186.76 has been setted!!");

  // 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);
  server_addr.sin_port = htons(portno);

  /*
   * 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:");

  /*
   * 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[4]);  //# get transmit time

  /*
   * 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;

  std::cout << "remote time is " << ctime(&tmit) << std::endl;

  char bufCurrentTime[32];
  char currentTime[64] = "date -s ";
  strftime(bufCurrentTime, sizeof(bufCurrentTime) - 1, " '%H:%M:%S %Y-%m-%d' ", localtime(&tmit));

  std::cout << "bufCurrentTime:" << bufCurrentTime << std::endl;

  for (int i = 0; i < 32; i++) {
    currentTime[8 + i] = bufCurrentTime[i];
  }

  std::cout << "currentTime:" << currentTime << std::endl;

  int setInSuccess = system(currentTime);
  if (setInSuccess != 0) {
    LOG("setTime is fail");
  }

  i = time(0);

  std::cout << "System time is " << (i - tmit) << " seconds off" << std::endl;
  return 0;
}

可能会报如下错误:

patten@patten-hp:~/diskTwo/demoCode/cppTime$ g++ getTime.cpp 
patten@patten-hp:~/diskTwo/demoCode/cppTime$ ./a.out 
socket: Success
sending data..
sendto: Success
recvfr:: Success
time is Wed Jun 19 15:33:51 2019

currentTime:date -s 2019/06/19
date: 无法设置日期: 不允许的操作
2019年 06月 19日 星期三 00:00:00 CST
{{getTime.cpp: Line 103:}}      setTime is fail
System time is -198251 seconds off

主要原因在于执行system指令时权限不够,所以执行该程序时,应该拥有root权限。

C++perror函数

  • C++中的errno变量,是用来记录错误类型。当调用,某些函数出错时,会自动设置errno的值。此时,可以利用perror,将errno错误输出。
  • 作用:将上一个函数发生的错误原因,输出到标准设备.

代码解析:

// 头文件
#include <stdio.h>

/* 函数原型
 * 参数str,指定要输出的字符串
 * 如 perror("Error:")
 * 输出 Error: error message
 */
void perror (const char* str)

// 例子
#include <stdio.h>
int main()
{
    FILE* fp;
    fp = fopen("/xxx/xxx", "r+");
    if (NULL == fp) {
        perror("Error: ");
    }
    return 0;
}

关联文章