Bootstrap

Linux使用 Netlink 捕获 USB 热插拔事件

1.前言

在 Qt 中使用 Netlink 来捕获 USB 热插拔事件需要结合 Qt 的事件循环机制和 Netlink 的底层接口。Netlink 是 Linux 内核和用户空间之间的一种通信机制,适用于捕获内核事件(例如 USB 设备的插拔事件)。

以下是一个使用 Qt 和 Netlink 捕获 USB 热插拔事件的示例。

2. 设置 Netlink 套接字

首先,我们需要设置一个 Netlink 套接字来接收内核发送的事件。

3. 将 Netlink 套接字与 Qt 的事件循环集成

使用 Qt 的 QSocketNotifier 类,可以将 Netlink 套接字集成到 Qt 的事件循环中,从而在事件发生时接收通知。

4. 处理 USB 插拔事件

处理 Netlink 消息并解析 USB 插拔事件。

5.代码示例

1.头文件 (usbmonitor.h)

#ifndef USBMONITOR_H
#define USBMONITOR_H

#include <QObject>
#include <QSocketNotifier>
#include <linux/netlink.h>
#include <sys/socket.h>

class USBMonitor : public QObject
{
    Q_OBJECT

public:
    USBMonitor(QObject *parent = nullptr);
    ~USBMonitor();

signals:
    void usbDeviceAdded();
    void usbDeviceRemoved();

private slots:
    void handleNetlinkMessage();

private:
    int netlinkSocket;
    QSocketNotifier *socketNotifier;

    void setupNetlinkSocket();
};

2.源文件(usbmonitor.cpp)

#include "usbmonitor.h"
#include <QDebug>
#include <unistd.h>

USBMonitor::USBMonitor(QObject *parent)
    : QObject(parent), netlinkSocket(-1), socketNotifier(nullptr)
{
    setupNetlinkSocket();
}

USBMonitor::~USBMonitor()
{
    if (socketNotifier) {
        delete socketNotifier;
    }
    if (netlinkSocket != -1) {
        close(netlinkSocket);
    }
}

void USBMonitor::setupNetlinkSocket()
{
    netlinkSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    if (netlinkSocket == -1) {
        qFatal("Failed to create Netlink socket");
    }

    sockaddr_nl sa;
    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_pid = getpid();
    sa.nl_groups = -1;

    if (bind(netlinkSocket, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
        qFatal("Failed to bind Netlink socket");
    }

    socketNotifier = new QSocketNotifier(netlinkSocket, QSocketNotifier::Read, this);
    connect(socketNotifier, &QSocketNotifier::activated, this, &USBMonitor::handleNetlinkMessage);
}

void USBMonitor::handleNetlinkMessage()
{
    char buffer[4096];
    int len = recv(netlinkSocket, buffer, sizeof(buffer), 0);
    if (len == -1) {
        qWarning("Failed to receive Netlink message");
        return;
    }

    buffer[len] = '\0';

    QString msg(buffer);
    if (msg.contains("add@")) {
        emit usbDeviceAdded();
    } else if (msg.contains("remove@")) {
        emit usbDeviceRemoved();
    }
}

3.使用示例 (main.cpp)

#include <QCoreApplication>
#include "usbmonitor.h"

void handleDeviceAdded() {
    qDebug() << "USB device added!";
}

void handleDeviceRemoved() {
    qDebug() << "USB device removed!";
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    USBMonitor monitor;
    QObject::connect(&monitor, &USBMonitor::usbDeviceAdded, &handleDeviceAdded);
    QObject::connect(&monitor, &USBMonitor::usbDeviceRemoved, &handleDeviceRemoved);

    return a.exec();
}

6.解释

1.USBMonitor 类:

  • 设置 Netlink 套接字并绑定到 NETLINK_KOBJECT_UEVENT 组。
  • 使用 QSocketNotifier 来监视 Netlink 套接字的可读事件。

2.handleNetlinkMessage 方法:

  • 从 Netlink 套接字接收消息并解析它们。
  • 根据消息内容,发射 usbDeviceAddedusbDeviceRemoved 信号。

3.main 函数:

  • 创建 USBMonitor 实例并连接信号到槽函数以处理 USB 插拔事件。

7.运行

编译并运行程序后,当插入或拔出 USB 设备时,你将在控制台上看到相应的消息。

这种方法结合了 Qt 的事件处理机制和 Linux

;