通过Netlink检测网线插拔

2019-11-02  本文已影响0人  网路元素

    最近有个需求需要检测RJ45网卡的网线有没有接上,而最近正在了解Netlink相关资料,刚好也看下通过Netlink可以进行检测,故在此做下粗略笔记:

    1.首先要创建一个Netlink Socket,在用户层使用如下参数来调用socket()函数:

       fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 

       上面这个函数第一个参数必须是AF_NETLINK或PF_NETLINK,这两个标志在Linux下是一样的,第二个参数可以是SOCK_RAW或SOCK_DGRAM(对应用到TCP或UDP协议),而最后一个参数NETLINK_ROUTE为“路由守护进程”,用于接收来自内核的路由通知事件。

    2.将上面创建的Socket绑定

addr.nl_family = AF_NETLINK;
addr.nl_groups = RTNLGRP_LINK; //指定接收路由多播组消息
bind(fd, (struct sockaddr*)&addr, sizeof(addr));

       上面将创建的socket与相应的协议族和组进行绑定,接下来通过读fd这个socket来获得相应的消息数据struct nlmsghdr,再对该结构体数据进行判断来获得网线是接上或是拔掉,相应的源码如下:

#include <sys/types.h> 
#include <sys/socket.h>
#include <asm/types.h> 
#include <linux/netlink.h> 
#include <linux/rtnetlink.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>

#define BUFLEN 20480

int main(int argc, char *argv[])
{
    int fd, retval;
    char buf[BUFLEN] = {0};

    int len = BUFLEN;
    struct sockaddr_nl addr;
    struct nlmsghdr *nh;
    struct ifinfomsg *ifinfo;
    struct rtattr *attr;

    fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
    memset(&addr, 0, sizeof(addr));

    addr.nl_family = AF_NETLINK;
    addr.nl_groups = RTNLGRP_LINK;
    bind(fd, (struct sockaddr*)&addr, sizeof(addr));

    while ((retval = read(fd, buf, BUFLEN)) > 0)
    {
        for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, retval); nh = NLMSG_NEXT(nh, retval))
        {
            if (nh->nlmsg_type == NLMSG_DONE)
                break;
            else if (nh->nlmsg_type == NLMSG_ERROR)
                return;
            else if (nh->nlmsg_type != RTM_NEWLINK)
                continue;

            ifinfo = NLMSG_DATA(nh);
            printf("%u: %s", ifinfo->ifi_index,  (ifinfo->ifi_flags & IFF_LOWER_UP) ? "up" : "down" );

            attr = (struct rtattr*)(((char*)nh) + NLMSG_SPACE(sizeof(*ifinfo)));
            len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));

            for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len))
            {
                if (attr->rta_type == IFLA_IFNAME)
                {
                    printf(" %s", (char*)RTA_DATA(attr));
                    break;
                }
            }

            printf("\n");
        }
    }
    return 0;
}

        将上面的代码保存成文件rj45_pulg_check.c,然后执行命令gcc -o rj45_pulg_check rj45_pulg_check.c进行编译,生成rj45_pulg_check文件,执行该文件后再插拔网线,有如下内容输出:

2: down eth0
2: up eth0

        注意:上述操作须在网卡驱动加载后进行,并且使用ifconfig里能看到该网卡信息(如没有则执行ifconfig eth0 up),实际上就相当于有没有分配到IP地址(即网络有没有通路)的判断。当我们开关WiFi时也可以检测到。

参考网址:

http://blog.csdn.net/sourthstar/article/details/7975999
http://blog.chinaunix.net/uid-317451-id-92692.html

上一篇下一篇

猜你喜欢

热点阅读