在Linux下监控网卡的连接状态有多种方式,我想要的方式,不是以轮询方式定时查询或主动获取某个值,而是在网卡连接状态变化时我的程序能收到通知。
具体做法如下:
使用AF_NETLINK socket 绑定到RTMGRP_LINK组 等待接收RTM_NEWLINK和RTM_DELLINK类型的message 解析收到的消息中ifinfomsg结构体的ifi_flags成员是否被设置了IFF_RUNNING1. –代码如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <string.h> #include <asm/types.h> #include <sys/socket.h> #include <sys/ioctl.h> //#include <net/if.h> #include <linux/if.h> #include <linux/if_arp.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #define PRINTF(fmt, …) printf(“%s:%d: ” fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__) #define BUF_SIZE 4096 static int init(struct sockaddr_nl *psa); static int deinit(); static int msg_req(); static int msg_loop(struct msghdr *pmh); static void sig_handler(int sig); static int sfd = -1; int main (int argc, char *argv[]) { int ret = 0; char buf[BUF_SIZE]; struct iovec iov = {buf, sizeof(buf)}; struct sockaddr_nl sa; struct msghdr msg = {(void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0}; ret = init(&sa); if (!ret) { ret = msg_req(); } if (!ret) { ret = msg_loop(&msg); } ret = deinit(); return ret; } static int init(struct sockaddr_nl *psa) { int ret = 0; struct sigaction sigact; sigact.sa_handler = sig_handler; if (!ret && -1 == sigemptyset(&sigact.sa_mask)) { PRINTF(“ERROR! sigemptyset\n”); ret = -1; } if (!ret && -1 == sigaction(SIGINT, &sigact, NULL)) { PRINTF(“ERROR! sigaction SIGINT\n”); ret = -1; } if (!ret && -1 == sigaction(SIGTERM, &sigact, NULL)) { PRINTF(“ERROR! sigaction SIGTERM\n”); ret = -1; } if (!ret) { sfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (-1 == sfd) { PRINTF(“ERROR! socket: %s\n”, strerror(errno)); ret = -1; } } memset(psa, 0, sizeof(*psa)); psa->nl_family = AF_NETLINK; psa->nl_groups = RTMGRP_LINK; if (!ret && bind(sfd, (struct sockaddr *)psa, sizeof(*psa))) { PRINTF(“ERROR! bind: %s\n”, strerror(errno)); ret = -1; } if (0 != ret) { deinit(); } return ret; } static int deinit() { int ret = 0; if (-1 != sfd) { if (-1 == close(sfd)) { PRINTF(“ERROR! close: %s\n”, strerror(errno)); ret = -1; } sfd = -1; } return ret; } static int msg_req() { int ret = 0; struct { struct nlmsghdr nh; struct ifinfomsg ifimsg; } req; memset(&req, 0, sizeof(req)); req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; req.nh.nlmsg_type = RTM_GETLINK; req.ifimsg.ifi_family = AF_UNSPEC; req.ifimsg.ifi_index = 0; req.ifimsg.ifi_change = 0xFFFFFFFF; if (-1 == send(sfd, &req, req.nh.nlmsg_len, 0)) { PRINTF(“ERROR! send: %s\n”, strerror(errno)); ret = -1; } return ret; } static int msg_loop(struct msghdr *pmh) { int ret = 0; ssize_t nread = -1; char *buf = (char *)(pmh->msg_iov->iov_base); struct nlmsghdr *nh; struct ifinfomsg *ifimsg; struct rtattr *rta; int attrlen; while (!ret) { nread = recvmsg(sfd, pmh, 0); if (-1 == nread) { PRINTF(“ERROR! recvmsg: %s\n”, strerror(errno)); ret = -1; } for (nh = (struct nlmsghdr *)buf; !ret && NLMSG_OK(nh, nread); nh = NLMSG_NEXT(nh, nread)) { if (NLMSG_DONE == nh->nlmsg_type) { break; } if (NLMSG_ERROR == nh->nlmsg_type) { PRINTF(“ERROR! NLMSG_ERROR\n”); ret = -1; } if (!ret && (RTM_NEWLINK == nh->nlmsg_type || RTM_DELLINK == nh->nlmsg_type)) { ifimsg = (struct ifinfomsg *)NLMSG_DATA(nh); if (ARPHRD_LOOPBACK != ifimsg->ifi_type) { attrlen = nh->nlmsg_len – NLMSG_LENGTH(sizeof(struct ifinfomsg)); for (rta = IFLA_RTA(ifimsg); RTA_OK(rta, attrlen) && rta->rta_type <= IFLA_MAX; rta = RTA_NEXT(rta, attrlen)) { if (IFLA_IFNAME == rta->rta_type) { printf(“%s: “, (char*)RTA_DATA(rta)); } } if (IFF_RUNNING & ifimsg->ifi_flags) printf(“link up\n”); else printf(“link down\n”); } } } } return ret; } static void sig_handler(int sig) { exit(deinit()); }<
免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:Linux 网口热插拔 https://www.yhzz.com.cn/a/22099.html