背景:项目需要实时监测网线的插拔状态,方法有很多,分为两大块。
- 轮询:可以轮询cat /sys/class/net/eth0/carrier的值,连接时为1,断开时为0。或者轮询使用shell查看ifconfig中对应网卡的状态是否RUNNING,但是轮询的方法非常耗费资源,需要开启一个全局定时器。
- 使用Netlink与内核交互,获取驱动上报的状态,此程序仅在应用层,前提是内核已有netLink的驱动。
.h
#include <QThread>
class netlinkmonitor:public QThread
{
Q_OBJECT
signals:
void usbNetworkIsChanged(bool);
void ethNetworkIsChanged(bool);
public:
explicit netlinkmonitor(QObject *parent = nullptr);
void run();
static netlinkmonitor *getInstance(){
if(!m_pinstance){
m_pinstance = new netlinkmonitor;
}
return m_pinstance;
}
private:
static a7netlinkmonitor *m_pinstance ;
};
.cpp
#include "netlinkmonitor.h"
#include "configFile.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>
#include <QDebug>
#define BUFLEN 20480
#define NETWORK_TYPE_USB "usb0"
#define NETWORK_TYPE_ETH "eth0"
a7netlinkmonitor *netlinkmonitor::m_pinstance = nullptr;
a7netlinkmonitor::netlinkmonitor(QObject *parent):QThread(parent)
{
m_pinstance = this;
}
void netlinkmonitor::run()
{
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 -1;
else if (nh->nlmsg_type != RTM_NEWLINK)
continue;
ifinfo = (struct ifinfomsg *)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");
SysConfig networkConfigWrite;
if(!strcmp((char*)RTA_DATA(attr), NETWORK_TYPE_USB)){
if((ifinfo->ifi_flags & IFF_LOWER_UP)){
emit m_pinstance->usbNetworkIsChanged(true);
}else{
emit m_pinstance->usbNetworkIsChanged(false);
}
networkConfigWrite.setValue("usb/status",(ifinfo->ifi_flags & IFF_LOWER_UP));
}
if(!strcmp((char*)RTA_DATA(attr), NETWORK_TYPE_ETH)){
if((ifinfo->ifi_flags & IFF_LOWER_UP)){
emit m_pinstance->ethNetworkIsChanged(true);
}else{
emit m_pinstance->ethNetworkIsChanged(false);
}
networkConfigWrite.setValue("lan/status",(ifinfo->ifi_flags & IFF_LOWER_UP));
}
}
}
}