2. WAN连接状态监测与状态转换
任务说明
实现WAN口连接状态监测状态机,以物理链路、DHCP地址获取、PPPoE拨号结果作为事件输入,驱动状态在断开(Disconnected)、连接中(Connecting)、已连接(Connected)之间转换,并输出当前状态供上层查询。
核心设计
状态机采用事件驱动模型,事件类型包括:LINK_UP(物理链路建立)、LINK_DOWN(物理链路断开)、DHCP_OK(DHCP获取地址成功)、DHCP_FAIL(DHCP超时或失败)、PPPOE_OK(PPPoE拨号成功)、PPPOE_FAIL(PPPoE拨号失败)。状态转换逻辑如下:
- 断开:收到
LINK_UP后进入连接中,并触发DHCP获取流程;收到其他事件保持断开。 - 连接中:若当前为DHCP阶段,收到
DHCP_OK则进入已连接,收到DHCP_FAIL则回退断开;若当前为PPPoE阶段,收到PPPOE_OK则进入已连接,收到PPPOE_FAIL则回退断开。任何阶段收到LINK_DOWN均回退断开。 - 已连接:收到
LINK_DOWN进入断开;收到其他事件保持已连接。
连接中状态内部区分DHCP阶段与PPPoE阶段,由conn_phase字段标识,初始进入连接中时为DHCP阶段,DHCP成功后若配置了PPPoE则切换为PPPoE阶段并触发拨号,否则直接进入已连接。
完整代码
#include <stdio.h>
#include <string.h>
typedef enum {
WAN_DISCONNECTED,
WAN_CONNECTING,
WAN_CONNECTED
} wan_state_t;
typedef enum {
EV_LINK_UP,
EV_LINK_DOWN,
EV_DHCP_OK,
EV_DHCP_FAIL,
EV_PPPOE_OK,
EV_PPPOE_FAIL
} wan_event_t;
typedef enum {
PHASE_DHCP,
PHASE_PPPOE
} conn_phase_t;
typedef struct {
wan_state_t state;
conn_phase_t phase;
int pppoe_enabled; /* 1表示需要PPPoE拨号 */
char ip_addr[16]; /* 获取到的IP地址 */
} wan_conn_t;
void wan_init(wan_conn_t *wan, int pppoe_enabled) {
memset(wan, 0, sizeof(*wan));
wan->state = WAN_DISCONNECTED;
wan->phase = PHASE_DHCP;
wan->pppoe_enabled = pppoe_enabled;
}
const char* state_name(wan_state_t s) {
switch (s) {
case WAN_DISCONNECTED: return "DISCONNECTED";
case WAN_CONNECTING: return "CONNECTING";
case WAN_CONNECTED: return "CONNECTED";
default: return "UNKNOWN";
}
}
/* 触发DHCP流程(实际环境中调用DHCP客户端) */
static void start_dhcp(wan_conn_t *wan) {
wan->phase = PHASE_DHCP;
printf("[ACTION] DHCP discover sent\n");
}
/* 触发PPPoE拨号流程 */
static void start_pppoe(wan_conn_t *wan) {
wan->phase = PHASE_PPPOE;
printf("[ACTION] PPPoE dial initiated\n");
}
void wan_handle_event(wan_conn_t *wan, wan_event_t ev) {
switch (wan->state) {
case WAN_DISCONNECTED:
if (ev == EV_LINK_UP) {
wan->state = WAN_CONNECTING;
start_dhcp(wan);
}
break;
case WAN_CONNECTING:
if (ev == EV_LINK_DOWN) {
wan->state = WAN_DISCONNECTED;
} else if (wan->phase == PHASE_DHCP) {
if (ev == EV_DHCP_OK) {
if (wan->pppoe_enabled) {
start_pppoe(wan);
} else {
strcpy(wan->ip_addr, "192.168.1.100");
wan->state = WAN_CONNECTED;
}
} else if (ev == EV_DHCP_FAIL) {
wan->state = WAN_DISCONNECTED;
}
} else if (wan->phase == PHASE_PPPOE) {
if (ev == EV_PPPOE_OK) {
strcpy(wan->ip_addr, "10.0.0.2");
wan->state = WAN_CONNECTED;
} else if (ev == EV_PPPOE_FAIL) {
wan->state = WAN_DISCONNECTED;
}
}
break;
case WAN_CONNECTED:
if (ev == EV_LINK_DOWN) {
wan->state = WAN_DISCONNECTED;
}
break;
}
}
/* 简单验证:模拟事件序列 */
int main() {
wan_conn_t wan;
wan_init(&wan, 1); /* 启用PPPoE */
printf("Init: %s\n", state_name(wan.state));
wan_handle_event(&wan, EV_LINK_UP);
printf("After LINK_UP: %s (phase=%s)\n",
state_name(wan.state),
wan.phase == PHASE_DHCP ? "DHCP" : "PPPoE");
wan_handle_event(&wan, EV_DHCP_OK);
printf("After DHCP_OK: %s (phase=%s)\n",
state_name(wan.state),
wan.phase == PHASE_DHCP ? "DHCP" : "PPPoE");
wan_handle_event(&wan, EV_PPPOE_OK);
printf("After PPPOE_OK: %s, IP=%s\n",
state_name(wan.state), wan.ip_addr);
wan_handle_event(&wan, EV_LINK_DOWN);
printf("After LINK_DOWN: %s\n", state_name(wan.state));
return 0;
}
编译与运行
gcc -o wan_state wan_state.c
./wan_state
验证方法
程序输出应依次为:Init: DISCONNECTED → After LINK_UP: CONNECTING (phase=DHCP) → After DHCP_OK: CONNECTING (phase=PPPoE) → After PPPOE_OK: CONNECTED, IP=10.0.0.2 → After LINK_DOWN: DISCONNECTED。若输出与上述一致,说明状态转换逻辑正确。可修改wan_init的pppoe_enabled参数为0,验证纯DHCP场景下DHCP_OK后直接进入CONNECTED且IP为192.168.1.100。
关键说明
代码中start_dhcp与start_pppoe仅打印动作日志,实际工程中应在此处调用真实DHCP客户端与PPPoE拨号模块,并在其回调中分别上报EV_DHCP_OK/FAIL与EV_PPPOE_OK/FAIL事件。IP地址赋值处为演示逻辑,实际应取自DHCP/PPPoE协商结果。