一,定时器1
继续上一章,dhcp客户端运行两个定时器,分别周期为1分钟的 void dhcp_coarse_tmr(void); 和 每周期为500ms的 void dhcp_fine_tmr(void);
先看dhcp_fine_tmr()定时任务
//处理dhcp请求超时
void
dhcp_fine_tmr()
{
struct netif *netif = netif_list;
//遍历所有网口
while (netif != NULL) {
if (netif->dhcp != NULL) {
//request_timeout -1,表示过去500ms
if (netif->dhcp->request_timeout > 1) {
netif->dhcp->request_timeout--;
}
else if (netif->dhcp->request_timeout == 1) {
//请求时间超时
netif->dhcp->request_timeout--; //此时timeout=0;
dhcp_timeout(netif); //执行超时处理
}
}
netif = netif->next; //检查下一个网口
}
}
当dhcp广播请求报文后就进入requesting状态,并设置request_timeout时间。在dhcp_fine_tmr()中,判断是否超时。dhcp_timeout()是超时处理函数:
static void
dhcp_timeout(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
//DHCP_BACKING_OFF和DHCP_SELECTING下超时是因为服务器们无响应,可能是广播的发现报文失踪了
if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
dhcp_discover(netif); //重新广播发现报文
//dhcp处于DHCP_REQUESTING状态而超时,可能是服务器的ack报文丢失
} else if (dhcp->state == DHCP_REQUESTING) {
if (dhcp->tries <= 5) {
//重新与该服务器联系,让她重新ack
dhcp_select(netif);
} else {
//该服务器可能挂了,我们重新广播发现报文,选择别的服务器
dhcp_release(netif); //清除之前的ip
dhcp_discover(netif);
}
}
//DHCP_RENEWING下,可能是再续约报文丢失
else if (dhcp->state == DHCP_RENEWING) {
dhcp_renew(netif); //重新发送续约报文
} else if (dhcp->state == DHCP_REBINDING) {
//重新绑定状态下,可能是报文丢失或服务器挂了
//超过8次无ack,就重新广播,选择其他服务器
if (dhcp->tries <= 8) {
dhcp_rebind(netif);
} else {
dhcp_release(netif); //释放资源
dhcp_discover(netif); //重新广播
}
} else if (dhcp->state == DHCP_REBOOTING) {
if (dhcp->tries < REBOOT_TRIES) {
dhcp_reboot(netif);
} else {
dhcp_discover(netif);
}
}
}
在超时处理函数中,超时的原因可能是报文丢失或服务器关闭等。所以针对超时的处理有报文重发和重新广播两种方式。
二 定时器2
通过dhcp协议获取的ip地址是有使用时间的。当过了租用时间的一半时,客户端要发送续约报文给服务器,通知服务器是否继续使用该ip地址;
client发送Rebind报文给任何可以用的服务器(Rebind报文中没有server id选项),以延长分配给client的地址的生存时间并且更新其它配置参数,这个消息是在发送Renew消息没有回应后才发送。
dhcp_coarse_tmr()定时器以一分钟的周期执行,检查续约时间和rebind时间是否超时,若超时则分别执行 dhcp_renew(netif); 和 dhcp_rebind(netif); 函数。
void
dhcp_coarse_tmr()
{
struct netif *netif = netif_list;
//遍历网口,检查t1,t2是否超时
while (netif != NULL) {
if (netif->dhcp != NULL) {
if (netif->dhcp->t2_timeout-- == 1) {
dhcp_t2_timeout(netif); //rebind超时
} else if (netif->dhcp->t1_timeout-- == 1) {
dhcp_t1_timeout(netif); //续约超时
}
}
netif = netif->next;
}
}