网络事件侦测
在网络传输的过程中,网络接口可能被增加或者删除,数据在传输过程中,链路突然断开等,以上这些突发情况,通常会对网络造成致命的错误。为了减少这些问题造成的损失,需要应用程序做一些应对的措施,例如,如果链路突然断开,应该等待网络恢复并重传,一些网络协议支持重传机制,但是它们都有一个共同的特点:重传的次数是有限制的。因此应该有一种机制:当网络恢复的时候通知应用程序进行重传,这种机制有以下一些优点:
- 网络断开后不会占用太多的 CPU 时间(轮询检测网络状态)。
- 能够及时地察觉网络的恢复(类似于中断机制)。
- 对于应用程序重传是可控的(网络协议不可控)。
SylixOS 实现了这种机制,它被称作网络事件侦测。通过操作 SylixOS 标准 I/O 设备“/dev/netevent”来侦测网络事件。这意味着可以像操作普通文件一样来操作此设备以获得网络的事件通知,应用程序唯一需要了解的是事件的帧格式,如下图所示。
一个 SylixOS 网络事件占用 24 个字节的空间,这意味着应用程序至少需要 24 个字节的空间来接收一个网络事件。在这 24 个字节中,前 4 个字节存放了事件的类型如下表所示,需要注意的是,事件类型以大端字节序存放在前 4 个字节中,事件类型后的 4 个字节存放了一个网络接口名(如 en1),其他空间存放了其他数据。通常应用程序可通过以下形式获得一个网络事件类型(buf 是应用程序接收缓冲区)。
event = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
SylixOS 支持如下表所示的网络事件。
网络事件类型 | 说明 |
---|---|
NET_EVENT_ADD | 网卡添加 |
NET_EVENT_REMOVE | 网卡删除 |
NET_EVENT_UP | 网卡使能 |
NET_EVENT_DOWN | 网卡禁能 |
NET_EVENT_LINK | 网卡已连接 |
NET_EVENT_UNLINK | 网卡断开连接 |
NET_EVENT_ADDR | 网卡地址变化 |
NET_EVENT_AUTH_FAIL | 网卡认证失败 |
NET_EVENT_AUTH_TO | 网卡认证超时 |
NET_EVENT_PPP_DEAD | 连接停止 |
NET_EVENT_PPP_INIT | 进入初始化过程 |
NET_EVENT_PPP_AUTH | 进入用户认证 |
NET_EVENT_PPP_RUN | 网络连通 |
NET_EVENT_PPP_DISCONN | 进入连接中断 |
NET_EVENT_WL_QUAL | 网卡无线环境变化(信号强度等) |
NET_EVENT_WL_SCAN | 无线网卡 AP 扫描结束 |
下面程序展示了应用程序如何侦测一个网络事件。在程序的实现中,首先打开设备 NET_EVENT_DEV_PATH 并安装 SIGALRM 信号,2 秒后使网卡禁能,read 函数读取网络事件并返回,最后打印网络接口和事件类型。
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <net/if_event.h>
void show_eventype (int event)
{
switch (event) {
case NET_EVENT_UP:
fprintf(stdout, "event: up.\n");
break;
case NET_EVENT_DOWN:
fprintf(stdout, "event: down.\n");
break;
case NET_EVENT_LINK:
fprintf(stdout, "event: link.\n");
break;
case NET_EVENT_UNLINK:
fprintf(stdout, "event: unlink.\n");
break;
default:
fprintf(stdout, "event unknown\n");
}
system("ifup en1");
}
void sig_handler (int signum)
{
system("ifdown en1");
}
int main (int argc, char *argv[])
{
int fd;
char buf[512];
char ifname[5];
ssize_t len;
int event;
fd = open(NET_EVENT_DEV_PATH, O_RDONLY);
if (fd < 0) {
perror("open");
return (-1);
}
signal(SIGALRM, sig_handler);
alarm(2);
len = read(fd, buf, 512);
if (len < 0) {
perror("read");
return (-1);
}
event = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
ifname[0] = buf[4];
ifname[1] = buf[5];
ifname[2] = buf[6];
ifname[3] = buf[7];
ifname[3] = 0;
fprintf(stdout, "ifname: %s\n", ifname);
show_eventype(event);
return (0);
}
在 SylixOS Shell 下运行程序,运行结果如下:
# ./Detect_network_events
net interface "en1" set down.
ifname: en1
event: down.
net interface "en1" set up.