QSocketNotifier 实现文件监控(demo Linux系统U盘插拔监控)

本文档介绍了QSocketNotifier如何实现对文件描述符的监控,特别是用于Linux系统中U盘等设备的插拔检测。QSocketNotifier提供读、写、异常三种类型的监控,并通过activated()信号触发相应处理。在实际应用中,如监控/proc/mounts文件变化,以实现文件系统变化的跟踪。

///////////////////////////QSocketNotifier文档翻译/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

QSocketNotifier 类提供了对文件的监控活动的支持。

QSocketNotifier 类使Qt的事件循环和文件描述器的事件循环结合起来成为可能。文件描述器的动作可以被Qt的主事件循环( QCoreApplication::exec() )检测到。


一旦你打开了一个设备使用低级的api(通常基于特定平台), 你可以创建一个socket notifier 来监控文件描述器。这个socket notifier可能是默认的,也就是说不管基于何种平台发生了一个socket event 他都会发出activated()信号。连接这个activated()信号到你槽,你可以据此来处理你的socket notifier根据不同的事件类型的相对应的反应。


这有三种类型的socket notifies: 读,写,和异常。这个类型描述是由Type的枚举类型定义的,而且这个类型在构造socket notifier的时候必须指定。在构造之后它可以通过使用这个type()函数来决定。

注意:如果你需要监控包括同已文件描述器的读和写的行为,你就必须创建两个socket notifiers。同样注意,不能在同一socket上面安装两个相同类型(读,写,异常)的socket notifiers。


setEnabled()函数可以允许你禁用或者启用这个socket notifier.  一般的建议是显示的启用或者禁用socket notifier,尤其是write notifiers。 如果禁用的notifier, 则会忽略socket events(也就是同样的效果不会创建socket notifier)。使用isEnable()可以决定notifier当前的状态。


最终,如果你使用socket()函数将会获取到socket的标识符。当然这个类也被叫做QSocketNotifier, 用来获取设备类型的socket的通知通常是使用他,而不是使用socket. QTcpSocket和QUdpSocket通过信号来提供通知,因此没有必要在他们使用时再使用QSocketNotifer来获取通知。

QSocketNotifier::QSocketNotifier(qintptr socketType typeQObject *parent = Q_NULLPTR)、

通过给定父类就可以构造一个socket notifier。他就可以使用socket, watches对给定类型进行监控。

通常建议显示的使用enable或者disable来启用或者禁用socket notifier,尤其是写的notifier。

Windows上的用户注意:这个socket传递给QSocketNotifier就会成为非阻塞的,即使创建的是一个阻塞的socket.

void QSocketNotifier::activated(int socket)

当socket监控的对应的socket事件发生时,就会发送这个信号。

这个socket的标识符就是传递的socket的参数。

注意:这是一个私有的信号,他可能被信号连接,但是不能由用户自己发出。

///////////////////////////QSocketNotifier文档翻译/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

以监控:/proc/mounts 文件变化为demo

volumemonitor.h

#ifndef VOLUMEMONITOR_H
#define VOLUMEMONITOR_H

#include <QObject>
#include <QSet>
#include <QSocketNotifier>

class VolumeMonitor : public QObject
{
    Q_OBJECT

public:
    VolumeMonitor(QObject *parent = 0);
    ~VolumeMonitor();

signals:
    void deviceAdded(const QString& addDev);
    void deviceRemoved(const QString& removeDe);

public slots:
    bool start();
    bool stop();
    bool isRunning();
    void onFileChanged();
private:
    int m_fileKde = -1;
    QSocketNotifier* m_socketNotifier;
    QSet<QString> m_fileContentSet;
};

#endif // VOLUMEMONITOR_H

volumemonitor.cpp

#include "volumemonitor.h"

#include <fcntl.h>
#include <unistd.h>
#include <QFile>
#include <QSet>
#include <QTextStream>
#include <QDebug>

namespace {
    const char mountFile[] = "/proc/mounts";
    QSet <QString> getMountFileContent() {
        QFile file(mountFile);
        QSet <QString> fileContentSet;
        if (file.exists()) {
            if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                QTextStream textStream(&file);
                QString fileContent = textStream.readAll();

                QStringList items = fileContent.split("\n");
                foreach (QString item, items) {
                        fileContentSet << item;
                }
                file.close();
            }
        }

        return fileContentSet;
    }

    QString getMountPoint(const QString& record) {
        const QStringList items = record.split(" ");
        if (items.length() > 4) {
            return items.at(1);
        } else {
            return "";
        }
    }
}

VolumeMonitor::VolumeMonitor(QObject *parent)
    : QObject(parent)
{
}

bool VolumeMonitor::start() {
    //get the set of mounted device's info;
    m_fileContentSet = getMountFileContent();

    m_fileKde = open(mountFile, O_RDONLY);
    if (m_fileKde == -1) {
        qWarning() << "open /proc/mounts failed!";
        return false;
    }

    m_socketNotifier = new QSocketNotifier(m_fileKde,
                                           QSocketNotifier::Write, this);

    connect(m_socketNotifier, &QSocketNotifier::activated,
            this, &VolumeMonitor::onFileChanged);
    return true;
}

bool VolumeMonitor::isRunning() {
    if (m_fileKde!= -1 && m_socketNotifier) {
        return true;
    } else {
        return false;
    }
}

bool VolumeMonitor::stop() {
    if (this->isRunning()) {
        close(m_fileKde);
        m_fileKde = -1;
        delete m_socketNotifier;
        m_socketNotifier = nullptr;
        return true;
    } else {
        return false;
    }
}
void VolumeMonitor::onFileChanged() {
    QSet <QString> changedItemSet = getMountFileContent();
    for(const QString& item: changedItemSet - m_fileContentSet)
        emit deviceAdded(getMountPoint(item));
    for(const QString& item: m_fileContentSet - changedItemSet)
        emit deviceRemoved(getMountPoint(item));


    m_fileContentSet = changedItemSet;
}

VolumeMonitor::~VolumeMonitor()
{
    this->stop();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值