文件更改句柄,QSocketNotifier 由于无效套接字而禁用

Posted

技术标签:

【中文标题】文件更改句柄,QSocketNotifier 由于无效套接字而禁用【英文标题】:File changes handle, QSocketNotifier disables due to invalid socket 【发布时间】:2012-10-13 21:25:17 【问题描述】:

我正在开发触摸屏,需要检测触摸事件以重新打开屏幕。我正在使用 Qt 和套接字,但遇到了一个有趣的问题。

每当我的 QSocketNotifier 检测到事件时,它都会向我发送关于它的无限通知。因此,我需要关闭并打开事件文件以循环通知程序(以下代码中的 inputNotifier)。问题通常在设备运行几分钟后出现,文件 (inputDevice) 突然将其句柄从 24 更改为其他值(通常为 17)。

我不确定该怎么做,因为初始连接语句链接到初始通知程序指针。如果我使用新句柄创建新通知程序,则连接无效。据我所知,没有选项可以在正在运行的 QSocketNotifier 上设置新的套接字值。建议?相关代码如下:

#include "backlightcontroller.h"
#include <QTimer>
#include <QFile>
#include <syslog.h>
#include <QDebug>
#include <QSocketNotifier>




BacklightController::BacklightController(QObject *parent) :
    QObject(parent)

    backlightActive = true;

    // setup timer
    trigger = new QTimer;
    trigger->setSingleShot(false);
    connect(trigger, SIGNAL(timeout()), SLOT(deactivateBacklight()));

    idleTimer = new QTimer;
    idleTimer->setInterval(IDLE_TIME * 1000);
    idleTimer->setSingleShot(false);
    connect(idleTimer, SIGNAL(timeout()), SIGNAL(idled()));
    idleTimer->start();

    // setup socket notifier
    inputDevice = new QFile(USERINPUT_DEVICE);
    if (!inputDevice->open(QIODevice::ReadOnly))
    
        syslog (LOG_ERR, "Input file for Backlight controller could not been opened.");
    
    else
    
        inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
        inputNotifier->setEnabled(true);
        connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
    

    qDebug()<<"backlight socket: "<<inputNotifier->socket();

    // read out settings-file
    QString intensity = Global::system_settings->getValue("BelatronUS_backlight_intensity");
    if (intensity.length() == 0) intensity = "100";
    QString duration = Global::system_settings->getValue("BelatronUS_backlight_duration");
    if (duration.length() == 0) duration = "180";
    QString always_on = Global::system_settings->getValue("BelatronUS_backlight_always_on");
    if (always_on.length() == 0) always_on = "0";

    setIntensity(intensity.toInt());
    setDuration(duration.toInt());

    if (always_on == "0")
      setAlwaysOn(false);
    else
      setAlwaysOn(true);



BacklightController::~BacklightController()

    trigger->stop();
    inputNotifier->setEnabled(false);
    inputDevice->close();

    delete trigger;
    delete inputDevice;
    delete inputNotifier;



void BacklightController::setCurrentIntensity(int intensity)

    // adapt backlight intensity
    QFile backlightFile("/sys/class/backlight/atmel-pwm-bl/brightness");
    if (!backlightFile.open(QIODevice::WriteOnly))
    
      syslog (LOG_ERR, "Backlight intensity file could not been opened.");
    
    else
    
      QString intensityString = QString::number(TO_BRIGHTNESS(intensity));
      if (backlightFile.write(
              qPrintable(intensityString), intensityString.length()
              ) < intensityString.length())
      
        syslog (LOG_ERR, "Backlight intensity could not been changed.");
      
      backlightFile.close();
    



void BacklightController::resetNotifier()


    inputDevice->close();
    if (!inputDevice->open(QIODevice::ReadOnly))
    
        syslog (LOG_ERR, "BacklightController::%s: Input file could not been opened.", __FUNCTION__);
    
    qDebug()<<"reset, handle: "<<inputDevice->handle();
    //inputNotifier=QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);


    // restart timer after user input
    idleTimer->start();



void BacklightController::activateBacklight()

    // only activate backlight, if it's off (avoid to useless fileaccess)
    if (!backlightActive)
    
        setCurrentIntensity(_intensity);
        backlightActive = true;
        emit backlightActivated();
    

    // restart backlight timeout, but only if we don't want the backlight to shine all the time
    if (!_alwaysOn)
        trigger->start();

    // reset notifier to be able to catch the next userinput
    resetNotifier();



void BacklightController::deactivateBacklight()

    // don't turn it off, if it's forced on
    if (!_alwaysOn)
    
        if (backlightActive)
        
            // only deactivate backlight, if it's on (avoid to useless fileaccess)
            setCurrentIntensity(BACKLIGHT_INTENSITY_OFF);
            backlightActive = false;
            emit backlightDeactivated();
        
    
    qDebug()<<"trigger stopping";
    trigger->stop();



void BacklightController::setIntensity(int intensity)

    if (intensity > 100)
        intensity = 100;
    else if (intensity < 0)
        intensity = 0;

    _intensity = intensity;

    // write new intensity to file if it's active at the moment
    if (backlightActive)
    
        setCurrentIntensity(_intensity);
        trigger->start();
    



void BacklightController::setDuration(int duration)

    if (duration < 1)
        duration = 1;

    _duration = duration;
    trigger->setInterval(_duration * MS_IN_SEC);

    // reset trigger after changing duration
    if (backlightActive)
    
        trigger->start();
    



void BacklightController::setAlwaysOn(bool always_on)

    _alwaysOn = always_on;

    // tell the timer what to to now
    if (_alwaysOn)
    
        this->activateBacklight();
        trigger->stop();
    
    else
    
        trigger->start();
    

【问题讨论】:

【参考方案1】:

我现在似乎找到了一个可行的解决方案。这不是最好的,所以如果有更好的解决方案,我会很想听听。我之前没有想到这一点的原因是因为我认为如果我在函数中有一个新的 connect 语句,它会在函数结束时限制范围。

解决方案是简单地检查文件中是否发生了句柄更改,然后使用该句柄为通知程序创建一个新指针。然后重新启用通知程序,因为它现在可能已被禁用,然后为指针创建一个新的连接语句。这是我使用的代码,添加在事件文件的关闭和重新打开下方:

if(inputDevice->handle()!=inputNotifier->socket())
    inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
    inputNotifier->setEnabled(true);
    connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));

【讨论】:

以上是关于文件更改句柄,QSocketNotifier 由于无效套接字而禁用的主要内容,如果未能解决你的问题,请参考以下文章

QSocketNotifier 与 nanomsg

QSocketNotifier 如何通知我管道已准备好读取?

更改Erlang文件句柄限制?

带有 Qt 5.12 QSocketNotifier 的 ZeroMQ 只触发一次

如何使用不同的类和导入动态地使用 Python 日志更改文件句柄

由于固定的 GC 句柄/没有可见的 gc 根导致内存泄漏