在client中,通过一个无限的for循环进入super loop,super loop中代码流程也和服务器的类似,先是建立socket监听,然后通过select+ FD_SET设置,同时对socket和pipe信号进行超时监听,随后根据state对接收到的packet进行处理和响应。
3.3.1 建立socket和pipe,并进行监听
初始化超时时间和rfds根据listen_mode开启socket监听设置rfds绑定socket fd和signal_pipe[0]select超时等待rfds下注册信号的发生。
tv.tv_sec = timeout - monotonic_sec();
jump_in:
tv.tv_usec = 0;
if (listen_mode != LISTEN_NONE && sockfd < 0) {
if (listen_mode == LISTEN_KERNEL)
sockfd = listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
else
sockfd = raw_socket(client_config.ifindex);
}
max_fd = udhcp_sp_fd_set(&rfds, sockfd);
retval = 0; /* If we already timed out, fall through, else... */
if (tv.tv_sec > 0) {
DEBUG("Waiting on select...");
retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
}
now = monotonic_sec();
if (retval < 0) {
/* EINTR? signal was caught, don't panic */
if (errno != EINTR) {
/* Else: an error occured, panic! */
bb_perror_msg_and_die("select");
}
} else if (retval == 0) {
retval是select函数的返回值,表示在定时tv时间内,信号集合rfds下注册fd中收到接收信号量的fd的个数,若retval为0,则表示在定时时间内没有fd收到接收信号量。或者,tv.tv_sec不大于0,即time_out<=time(0),已经超时,则也设置retval为0.
3.3.2 超时未收到信号
如果retval=0,则表示在定时期限内,没有收到socket和signal信号,则根据DHCP协议中对客户端行为的定义,依据状态执行操作。
/* timeout dropped to zero */
switch (state) {
case INIT_SELECTING:
if (packet_num < client_config.retries) {
if (packet_num == 0)
xid = random_xid();
/* send discover packet */
send_discover(xid, requested_ip); /* broadcast */
timeout = now + client_config.timeout;
packet_num++;
} else {
udhcp_run_script(NULL, "leasefail");