Linux_NTP 网络同步 -> ntpd / CDH6

 

参考文章:

 

解决CentOS7下用ntpdate同步时间问题

https://blog.youkuaiyun.com/qq_27754983/article/details/69386408

 

Linux配置ntp时间服务器(全)

https://www.cnblogs.com/quchunhui/p/7658853.html

 

Cloudera 建议使用 NTP 使 Hadoop 群集实现时间同步

http://www.cnblogs.com/tmeily/p/4422604.html

 

在安装CDH 的时候,我们需要配置 时间同步。本篇文章将会讲解如何配置网络时间同步。

 

0.ntp 的作用

1.确认是否需要安装

2.安装服务

3.配置ntp服务

4.启动服务,查看服务状态,开机自启动

5.手动设置定时任务,进行时间同步 (感觉可以废弃)

6.可用的ntp服务器地址

7.注意事项

 

0.ntp 的作用

NTP  的全称 : Network Time Protocol (NTP)

时间服务器作用:


       大数据产生与处理系统是各种计算设备集群的,计算设备将统一、同步的标准时间用于记录各种事件发生时序,如E-MAIL信息、文件创建和访问时间、数据库处理时间等。

      大数据系统内不同计算设备之间控制、计算、处理、应用等数据或操作都具有时序性,若计算机时间不同步,这些应用或操作或 将无法正常进行。

       大数据系统是对时间敏感的计算处理系统,时间同步是大数据能够得到正确处理的基础保障,是大数据得以发挥作用的技术支撑。

   大数据时代,整个处理计算系统内的大数据通信都是通过网络进行。

   时间同步也是如此,利用大数据的互联网络传送标准时间信息,实现大数据系统内时间同步。

   网络时间同步协议(NTP)是时间同步的技术基础。

 

 

1.确认是否需要安装

     首先是安装 ntp 服务, 我们的操作系统是 Centos7 , 使用 rpm 管理。首先,查看下我们是否已经安装了该服务,

执行以下命令。 

rpm –qa | grep ntp

在我们的主机,执行效果如下:

[root@cdh-manager sbin]# rpm -qa | grep ntp
ntp-4.2.6p5-28.el7.centos.x86_64
fontpackages-filesystem-1.44-8.el7.noarch
ntpdate-4.2.6p5-28.el7.centos.x86_64
python-ntplib-0.3.2-1.el7.noarch
You have new mail in /var/spool/mail/root

 

若只有ntpdate而未见ntp,则需删除原有ntpdate。如:

ntpdate-4.2.6p5-22.el7_0.x86_64
fontpackages-filesystem-1.44-8.el7.noarch
python-ntplib-0.3.2-1.el7.noarch

 

2)删除已安装ntp
【命令】yum –y remove ntpdate-4.2.6p5-22.el7.x86_64

 

3)重新安装ntp
【命令】yum –y install ntp

 

2.安装服务

 

Install NTP.

  • RHEL compatible:
    yum install ntp
  • SLES:
    zypper install ntp
  • Ubuntu:
    apt-get install ntp

 

3.配置ntp服务

 

1)修改所有节点的/etc/ntp.conf

【命令】vi /etc/ntp.conf

【内容】

restrict 192.168.6.3 nomodify notrap nopeer noquery          //当前节点IP地址

restrict 192.168.6.2 mask 255.255.255.0 nomodify notrap  //集群所在网段的网关(Gateway),子网掩码(Genmask)

 

2)选择一个主节点,修改其/etc/ntp.conf

【命令】vi /etc/ntp.conf

【内容】在server部分添加一下部分,并注释掉server 0 ~ n

server 127.127.1.0

Fudge 127.127.1.0 stratum 10

 

3)主节点以外,继续修改/etc/ntp.conf

【命令】vi /etc/ntp.conf

【内容】在server部分添加如下语句,将server指向主节点。

server 192.168.6.3

Fudge 192.168.6.3 stratum 10

 

 

修改前,各个节点:

 

修改后:

主节点:

# For more information about this file, see the man pages
# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).

driftfile /var/lib/ntp/drift

# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
restrict default nomodify notrap nopeer noquery

# Permit all access over the loopback interface.  This could
# be tightened as well, but to do so would effect some of
# the administrative functions.
#当前节点IP地址
restrict 192.168.75.133 nomodify notrap nopeer noquery
restrict 127.0.0.1 
restrict ::1


# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
#集群所在网段的网关(Gateway),子网掩码(Genmask)
restrict 192.168.75.2 mask 255.255.255.0 nomodify notrap


# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).

#old config
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

server 127.127.1.0
Fudge 127.127.1.0 stratum 10


#broadcast 192.168.1.255 autokey	# broadcast server
#broadcastclient			# broadcast client
#broadcast 224.0.1.1 autokey		# multicast server
#multicastclient 224.0.1.1		# multicast client
#manycastserver 239.255.254.254		# manycast server
#manycastclient 239.255.254.254 autokey # manycast client

# Enable public key cryptography.
#crypto

includefile /etc/ntp/crypto/pw

# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography. 
keys /etc/ntp/keys

# Specify the key identifiers which are trusted.
#trustedkey 4 8 42

# Specify the key identifier to use with the ntpdc utility.
#requestkey 8

# Specify the key identifier to use with the ntpq utility.
#controlkey 8

# Enable writing of statistics records.
#statistics clockstats cryptostats loopstats peerstats

# Disable the monitoring facility to prevent amplification attacks using ntpdc
# monlist command when default restrict does not include the noquery flag. See
# CVE-2013-5211 for more details.
# Note: Monitoring will not be disabled with the limited restriction flag.
disable monitor

 

从节点:

# For more information about this file, see the man pages
# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).

driftfile /var/lib/ntp/drift

# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
restrict default nomodify notrap nopeer noquery

# Permit all access over the loopback interface.  This could
# be tightened as well, but to do so would effect some of
# the administrative functions.
#当前节点IP地址
restrict 192.168.75.132 nomodify notrap nopeer noquery
restrict 127.0.0.1 
restrict ::1

# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
#集群所在网段的网关(Gateway),子网掩码(Genmask)
restrict 192.168.75.2 mask 255.255.255.0 nomodify notrap

# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
server 192.168.75.133
Fudge 192.168.75.133 stratum 10

#broadcast 192.168.1.255 autokey	# broadcast server
#broadcastclient			# broadcast client
#broadcast 224.0.1.1 autokey		# multicast server
#multicastclient 224.0.1.1		# multicast client
#manycastserver 239.255.254.254		# manycast server
#manycastclient 239.255.254.254 autokey # manycast client

# Enable public key cryptography.
#crypto

includefile /etc/ntp/crypto/pw

# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography. 
keys /etc/ntp/keys

# Specify the key identifiers which are trusted.
#trustedkey 4 8 42

# Specify the key identifier to use with the ntpdc utility.
#requestkey 8

# Specify the key identifier to use with the ntpq utility.
#controlkey 8

# Enable writing of statistics records.
#statistics clockstats cryptostats loopstats peerstats

# Disable the monitoring facility to prevent amplification attacks using ntpdc
# monlist command when default restrict does not include the noquery flag. See
# CVE-2013-5211 for more details.
# Note: Monitoring will not be disabled with the limited restriction flag.
disable monitor

 

4.启动服务,查看服务状态,开机自启动

 

由于我们是 centos7, 启动服务,我们通过以下指令:

systemctl start ntpd

 

设置开机启动

Configure the NTP service to run at boot:

  • RHEL 7 Compatible:
    sudo systemctl enable ntpd
  • RHEL 6 Compatible, SLES, Ubuntu:
    chkconfig ntpd on

 

查看服务状态:

systemctl status ntpd

[root@cdh-manager 6.0.1]# systemctl status ntpd
● ntpd.service - Network Time Service
   Loaded: loaded (/usr/lib/systemd/system/ntpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2018-12-11 05:46:05 EST; 3h 36min ago
 Main PID: 84771 (ntpd)
    Tasks: 1
   CGroup: /system.slice/ntpd.service
           └─84771 /usr/sbin/ntpd -u ntp:ntp -g

Dec 11 05:46:05 cdh-manager ntpd[84771]: Listen normally on 4 virbr0 192.168.122.1 UDP 123
Dec 11 05:46:05 cdh-manager ntpd[84771]: Listen normally on 5 lo ::1 UDP 123
Dec 11 05:46:05 cdh-manager ntpd[84771]: Listen normally on 6 ens33 fe80::20c:29ff:fee8:72fb UDP 123
Dec 11 05:46:05 cdh-manager ntpd[84771]: Listening on routing socket on fd #23 for interface updates
Dec 11 05:46:05 cdh-manager ntpd[84771]: 0.0.0.0 c016 06 restart
Dec 11 05:46:05 cdh-manager ntpd[84771]: 0.0.0.0 c012 02 freq_set kernel 0.000 PPM
Dec 11 05:46:05 cdh-manager ntpd[84771]: 0.0.0.0 c011 01 freq_not_set
Dec 11 05:46:06 cdh-manager ntpd[84771]: 0.0.0.0 c514 04 freq_mode
Dec 11 06:02:06 cdh-manager ntpd[84771]: 0.0.0.0 0512 02 freq_set kernel 0.000 PPM
Dec 11 06:02:06 cdh-manager ntpd[84771]: 0.0.0.0 0515 05 clock_sync

 

 

对 ntp 自己的服务状态我们还可以进行更细致的查询:

 

【命令】ntpstat

 

查看ntp状态时,可能会出现如下所示情况

① unsynchronised time server re-starting polling server every 8 s

 

② unsynchronised polling server every 8 s

 

这种情况属于正常,ntp服务器配置完毕后,需要等待5-10分钟才能与/etc/ntp.conf中配置的标准时间进行同步。

等一段时间之后,再次使用ntpstat命令查看状态,就会变成如下正常结果:

 

 

3)查看ntp服务器与上层ntp的状态

【命令】ntpq -p

主机点上:

从节点上:

 

  • "* ":响应的NTP服务器和最精确的服务器。
  • "+":响应这个查询请求的NTP服务器。
  • "blank(空格)":没有响应的NTP服务器。
  • "remote" :响应这个请求的NTP服务器的名称。
  • "refid ":NTP服务器使用的更高一级服务器的名称。
  • "st":正在响应请求的NTP服务器的级别。
  • "when":上一次成功请求之后到现在的秒数。
  • "poll":当前的请求的时钟间隔的秒数。
  • "offset":主机通过NTP时钟同步与所同步时间源的时间偏移量,单位为毫秒(ms)。

 

5.手动设置定时任务,进行时间同步

从上面可以看出,我们其实并不需要配置定时同步任务,只需要主节点同步网络时间即可

[root@cdh-manager 6.0.1]# crontab -l
0-59/10 * * * * /usr/sbin/ntpdate -u asia.pool.ntp.org

 

6.可用的ntp服务器地址

经验证通过的NTP 地址:

asia.pool.ntp.org 

 

7.注意事项

 

===restrict选项格式===

restrict [ 客户端IP ]  mask  [ IP掩码 ]  [参数]

“客户端IP” 和 “IP掩码” 指定了对网络中哪些范围的计算机进行控制,如果使用default关键字,则表示对所有的计算机进行控制,参数指定了具体的限制内容,常见的参数如下:

◆ ignore:拒绝连接到NTP服务器

◆ nomodiy: 客户端不能更改服务端的时间参数,但是客户端可以通过服务端进行网络校时。

◆ noquery: 不提供客户端的时间查询

◆ notrap: 不提供trap远程登录功能,trap服务是一种远程时间日志服务。

◆ notrust: 客户端除非通过认证,否则该客户端来源将被视为不信任子网 。

◆ nopeer: 提供时间服务,但不作为对等体。

◆ kod: 向不安全的访问者发送Kiss-Of-Death报文。

  

===server选项格式===

server host  [ key n ] [ version n ] [ prefer ] [ mode n ] [ minpoll n ] [ maxpoll n ] [ iburst ]

其中host是上层NTP服务器的IP地址或域名,随后所跟的参数解释如下所示:

◆ key: 表示所有发往服务器的报文包含有秘钥加密的认证信息,n是32位的整数,表示秘钥号。

◆ version: 表示发往上层服务器的报文使用的版本号,n默认是3,可以是1或者2。

◆ prefer: 如果有多个server选项,具有该参数的服务器有限使用。

◆ mode: 指定数据报文mode字段的值。

◆ minpoll: 指定与查询该服务器的最小时间间隔为2的n次方秒,n默认为6,范围为4-14。

◆ maxpoll:  指定与查询该服务器的最大时间间隔为2的n次方秒,n默认为10,范围为4-14。

◆ iburst: 当初始同步请求时,采用突发方式接连发送8个报文,时间间隔为2秒。

 

===查看网关方法===

【命令1】route -n  

【命令2】ip route show  

【命令3】netstat -r

 

===层次(stratum)===

stratum根据上层server的层次而设定(+1)。

对于提供network time service provider的主机来说,stratum的设定要尽可能准确。

而作为局域网的time service provider,通常将stratum设置为10

 

0层的服务器采用的是原子钟、GPS钟等物理设备,stratum 1与stratum 0 是直接相连的,

往后的stratum与上一层stratum通过网络相连,同一层的server也可以交互。

ntpd对下层client来说是service server,对于上层server来说它是client。

ntpd根据配置文件的参数决定是要为其他服务器提供时钟服务或者是从其他服务器同步时钟。所有的配置都在/etc/ntp.conf文件中。

这里写图片描述

 

===注意防火墙屏蔽ntp端口===

ntp服务器默认端口是123,如果防火墙是开启状态,在一些操作可能会出现错误,所以要记住关闭防火墙。

 

===同步硬件时钟===

ntp服务,默认只会同步系统时间。

如果想要让ntp同时同步硬件时间,可以设置/etc/sysconfig/ntpd文件,

在/etc/sysconfig/ntpd文件中,添加【SYNC_HWCLOCK=yes】这样,就可以让硬件时间与系统时间一起同步。

允许BIOS与系统时间同步,也可以通过hwclock -w 命令。

 

===ntpd、ntpdate的区别===

下面是网上关于ntpd与ntpdate区别的相关资料。如下所示所示:

使用之前得弄清楚一个问题,ntpd与ntpdate在更新时间时有什么区别。

ntpd不仅仅是时间同步服务器,它还可以做客户端与标准时间服务器进行同步时间,而且是平滑同步,

并非ntpdate立即同步,在生产环境中慎用ntpdate,也正如此两者不可同时运行。

时钟的跃变,对于某些程序会导致很严重的问题。

 

许多应用程序依赖连续的时钟——毕竟,这是一项常见的假定,即,取得的时间是线性的,

一些操作,例如数据库事务,通常会地依赖这样的事实:时间不会往回跳跃。

不幸的是,ntpdate调整时间的方式就是我们所说的”跃变“:在获得一个时间之后,ntpdate使用settimeofday(2)设置系统时间,

这有几个非常明显的问题:

【一】这样做不安全。

ntpdate的设置依赖于ntp服务器的安全性,攻击者可以利用一些软件设计上的缺陷,拿下ntp服务器并令与其同步的服务器执行某些消耗性的任务。

由于ntpdate采用的方式是跳变,跟随它的服务器无法知道是否发生了异常(时间不一样的时候,唯一的办法是以服务器为准)。

【二】这样做不精确。

一旦ntp服务器宕机,跟随它的服务器也就会无法同步时间。

与此不同,ntpd不仅能够校准计算机的时间,而且能够校准计算机的时钟。

【三】这样做不够优雅。

由于是跳变,而不是使时间变快或变慢,依赖时序的程序会出错

(例如,如果ntpdate发现你的时间快了,则可能会经历两个相同的时刻,对某些应用而言,这是致命的)。

因而,唯一一个可以令时间发生跳变的点,是计算机刚刚启动,但还没有启动很多服务的那个时候。

其余的时候,理想的做法是使用ntpd来校准时钟,而不是调整计算机时钟上的时间。

NTPD在和时间服务器的同步过程中,会把BIOS计时器的振荡频率偏差——或者说Local Clock的自然漂移(drift)——记录下来。

这样即使网络有问题,本机仍然能维持一个相当精确的走时。

int ntpd_main(int argc UNUSED_PARAM, char **argv) { #undef G struct globals G; struct pollfd *pfd; peer_t **idx2peer; unsigned cnt; memset(&G, 0, sizeof(G)); SET_PTR_TO_GLOBALS(&G); ntp_init(argv); /* If ENABLE_FEATURE_NTPD_SERVER, + 1 for listen_fd: */ cnt = G.peer_cnt + ENABLE_FEATURE_NTPD_SERVER; idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt); pfd = xzalloc(sizeof(pfd[0]) * cnt); /* Countdown: we never sync before we sent INITIAL_SAMPLES+1 * packets to each peer. * NB: if some peer is not responding, we may end up sending * fewer packets to it and more to other peers. * NB2: sync usually happens using INITIAL_SAMPLES packets, * since last reply does not come back instantaneously. */ cnt = G.peer_cnt * (INITIAL_SAMPLES + 1); while (!bb_got_signal) { llist_t *item; unsigned i, j; int nfds, timeout; double nextaction; /* Nothing between here and poll() blocks for any significant time */ nextaction = G.last_script_run + (11*60); if (nextaction < G.cur_time + 1) nextaction = G.cur_time + 1; i = 0; #if ENABLE_FEATURE_NTPD_SERVER if (G_listen_fd != -1) { pfd[0].fd = G_listen_fd; pfd[0].events = POLLIN; i++; } #endif /* Pass over peer list, send requests, time out on receives */ for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *p = (peer_t *) item->data; if (p->next_action_time <= G.cur_time) { if (p->p_fd == -1) { /* Time to send new req */ if (--cnt == 0) { VERB4 bb_simple_error_msg("disabling burst mode"); G.polladj_count = 0; G.poll_exp = MINPOLL; } send_query_to_peer(p); } else { /* Timed out waiting for reply */ close(p->p_fd); p->p_fd = -1; /* If poll interval is small, increase it */ if (G.poll_exp < BIGPOLL) adjust_poll(MINPOLL); timeout = poll_interval(NOREPLY_INTERVAL); bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us", p->p_dotted, p->reachable_bits, timeout); /* What if don't see it because it changed its IP? */ if (p->reachable_bits == 0) resolve_peer_hostname(p); set_next(p, timeout); } } if (p->next_action_time < nextaction) nextaction = p->next_action_time; if (p->p_fd >= 0) { /* Wait for reply from this peer */ pfd[i].fd = p->p_fd; pfd[i].events = POLLIN; idx2peer[i] = p; i++; } } timeout = nextaction - G.cur_time; if (timeout < 0) timeout = 0; timeout++; /* (nextaction - G.cur_time) rounds down, compensating */ /* Here we may block */ VERB2 { if (i > (ENABLE_FEATURE_NTPD_SERVER && G_listen_fd != -1)) { /* We wait for at least one reply. * Poll for it, without wasting time for message. * Since replies often come under 1 second, this also * reduces clutter in logs. */ nfds = poll(pfd, i, 1000); if (nfds != 0) goto did_poll; if (--timeout <= 0) goto did_poll; } bb_error_msg("poll:%us sockets:%u interval:%us", timeout, i, 1 << G.poll_exp); } nfds = poll(pfd, i, timeout * 1000); did_poll: gettime1900d(); /* sets G.cur_time */ if (nfds <= 0) { double ct; int dns_error; if (bb_got_signal) break; /* poll was interrupted by a signal */ if (G.cur_time - G.last_script_run > 11*60) { /* Useful for updating battery-backed RTC and such */ run_script("periodic", G.last_update_offset); gettime1900d(); /* sets G.cur_time */ } /* Resolve peer names to IPs, if not resolved yet. * We do it only when poll timed out: * this way, we almost never overlap DNS resolution with * "request-reply" packet round trip. */ dns_error = 0; ct = G.cur_time; for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *p = (peer_t *) item->data; if (p->next_action_time <= ct && !p->p_lsa) { /* This can take up to ~10 sec per each DNS query */ dns_error |= (!resolve_peer_hostname(p)); } } if (!dns_error) goto check_unsync; /* Set next time for those which are still not resolved */ gettime1900d(); /* sets G.cur_time (needed for set_next()) */ for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *p = (peer_t *) item->data; if (p->next_action_time <= ct && !p->p_lsa) { set_next(p, HOSTNAME_INTERVAL * p->dns_errors); } } goto check_unsync; } /* Process any received packets */ j = 0; #if ENABLE_FEATURE_NTPD_SERVER if (G.listen_fd != -1) { if (pfd[0].revents /* & (POLLIN|POLLERR)*/) { nfds--; recv_and_process_client_pkt(/*G.listen_fd*/); gettime1900d(); /* sets G.cur_time */ } j = 1; } #endif for (; nfds != 0 && j < i; j++) { if (pfd[j].revents /* & (POLLIN|POLLERR)*/) { /* * At init, alarm was set to 10 sec. * Now we did get a reply. * Increase timeout to 50 seconds to finish syncing. */ if (option_mask32 & OPT_qq) { option_mask32 &= ~OPT_qq; alarm(50); } nfds--; recv_and_process_peer_pkt(idx2peer[j]); gettime1900d(); /* sets G.cur_time */ } } check_unsync: if (G.ntp_peers && G.stratum != MAXSTRAT) { for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *p = (peer_t *) item->data; if (p->reachable_bits) goto have_reachable_peer; } /* No peer responded for last 8 packets, panic */ clamp_pollexp_and_set_MAXSTRAT(); run_script("unsync", 0.0); have_reachable_peer: ; } } /* while (!bb_got_signal) */ remove_pidfile_std_path_and_ext("ntpd"); kill_myself_with_sig(bb_got_signal); }
最新发布
07-12
<think>好的,我现在需要分析用户提供的这段ntpd_main函数的代码,并生成相应的解释和相关问题。首先,我要理解这段代码的功能和结构。看起来这是ntpd网络时间协议守护进程)的主函数,负责处理时间同步网络通信、超时重试等机制。 首先,代码开头定义了全局变量结构体G,初始化poll文件描述符数组和对等节点数组。然后进入主循环,处理信号、发送NTP请求、接收响应、处理超时和DNS解析等。 接下来,我需要分步骤解析代码的关键部分: 1. **全局变量和资源初始化**:包括poll文件描述符数组、对等节点数组的分配,以及NTP初始化。 2. **主循环结构**:处理信号中断、定时任务、发送请求、接收响应、超时处理、DNS解析。 3. **网络通信**:使用poll等待文件描述符事件,处理客户端和对等节点的数据包。 4. **超时和重试机制**:当请求超时时,关闭文件描述符,调整轮询间隔,并重新解析主机名。 5. **DNS解析**:在超时后尝试解析未解析的对等节点主机名,处理可能的DNS错误。 6. **周期性脚本执行**:定期运行脚本更新硬件时钟。 7. **状态检查和同步**:检查是否有可到达的对等节点,否则进入非同步状态并运行脚本。 8. **清理和退出**:移除PID文件,处理信号退出。 在解析过程中,需要注意代码中的条件编译(如ENABLE_FEATURE_NTPD_SERVER),以及各种宏和函数的作用,比如VERB级别的日志输出、alarm设置、poll调用等。 接下来,我需要考虑用户可能关心的问题,比如代码中的关键机制、潜在问题、优化点或实现细节。例如,为什么使用poll而不是select?如何处理多个对等节点的请求?DNS解析失败后的重试策略是什么?还有,关于时间同步的算法和周期性脚本的作用等。 此外,还要注意代码中的注释和变量命名,确保理解每个部分的具体功能。例如,cnt变量用于控制初始数据包的数量,G.poll_exp控制轮询间隔,idx2peer数组用于关联poll文件描述符和对应的对等节点等。 最后,生成相关问题时,需要涵盖代码的不同方面,包括设计决策、错误处理、性能优化、可移植性、安全性和扩展功能等。确保问题具有针对性,能够帮助用户深入理解代码的实现细节和潜在考量。 </think>该函数实现了NTP守护进程的核心逻辑,包含网络通信、时间同步和状态管理三大模块。以下是代码结构化解析: ```c int ntpd_main(int argc UNUSED_PARAM, char **argv) { // 全局变量初始化 struct globals G; struct pollfd *pfd; peer_t **idx2peer; unsigned cnt; memset(&G, 0, sizeof(G)); SET_PTR_TO_GLOBALS(&G); ntp_init(argv); // 初始化NTP配置和套接字 // 资源分配:根据对等节点数量+服务器模式扩展 cnt = G.peer_cnt + ENABLE_FEATURE_NTPD_SERVER; idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt); pfd = xzalloc(sizeof(pfd[0]) * cnt); // 初始数据包计数器(每个peer发送INITIAL_SAMPLES+1个包) cnt = G.peer_cnt * (INITIAL_SAMPLES + 1); while (!bb_got_signal) { double nextaction = G.last_script_run + (11*60); if (nextaction < G.cur_time + 1) nextaction = G.cur_time + 1; // 轮询文件描述符索引初始化 unsigned i = 0; #if ENABLE_FEATURE_NTPD_SERVER if (G_listen_fd != -1) { pfd[0].fd = G_listen_fd; // 监听套接字 pfd[0].events = POLLIN; i++; } #endif // 主要处理逻辑:发送请求/处理超时 for (llist_t *item = G.ntp_peers; item != NULL; item = item->link) { peer_t *p = (peer_t *) item->data; // 触发动作时机判断 if (p->next_action_time <= G.cur_time) { if (p->p_fd == -1) { if (--cnt == 0) { /* 进入普通模式 */ } send_query_to_peer(p); // 发送NTP请求 } else { // 接收超时处理 close(p->p_fd); p->p_fd = -1; adjust_poll(MINPOLL); // 缩短轮询间隔 resolve_peer_hostname(p); // DNS重解析 set_next(p, timeout); } } // 更新最近动作时间 if (p->next_action_time < nextaction) nextaction = p->next_action_time; // 注册有效套接字到poll if (p->p_fd >= 0) { pfd[i].fd = p->p_fd; pfd[i].events = POLLIN; idx2peer[i++] = p; } } // 计算超时时间并执行poll int timeout = nextaction - G.cur_time + 1; nfds = poll(pfd, i, timeout * 1000); // 处理poll结果 if (nfds <= 0) { // 超时处理:周期性脚本执行/DNS解析 if (G.cur_time - G.last_script_run > 11*60) { run_script("periodic", G.last_update_offset); // 硬件时钟更新 } // DNS解析重试机制 for (llist_t *item = G.ntp_peers; item != NULL; item = item->link) { peer_t *p = (peer_t *) item->data; if (p->next_action_time <= G.cur_time && !p->p_lsa) { dns_error |= (!resolve_peer_hostname(p)); // 非阻塞DNS解析 } } } else { // 数据包处理 for (int j = 0; nfds != 0 && j < i; j++) { if (pfd[j].revents) { recv_and_process_peer_pkt(idx2peer[j]); // 解析NTP响应 } } } // 同步状态检查 if (G.ntp_peers && G.stratum != MAXSTRAT) { for (llist_t *item = G.ntp_peers; item != NULL; item = item->link) { if (peer_t *p = item->data->reachable_bits) { goto have_reachable_peer; } } clamp_pollexp_and_set_MAXSTRAT(); // 进入非同步状态 run_script("unsync", 0.0); } } // 清理退出 remove_pidfile_std_path_and_ext("ntpd"); kill_myself_with_sig(bb_got_signal); } ``` **核心机制解析:** 1. **双模式运行**:支持客户端请求处理(通过监听套接字)和对等节点同步 2. **动态轮询机制**:根据网络状况自动调整轮询间隔(MINPOLL-BIGPOLL) 3. **分级超时处理**:请求超时立即重试,DNS解析失败采用指数退避策略 4. **状态同步算法**:通过reachable_bits位图维护对等节点可达性状态 5. **渐进式同步**:初始阶段密集采样(INITIAL_SAMPLES),稳定后降低频率 6. **安全退出机制**:清理PID文件并优雅处理信号中断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值