Ravikumar Tulugu
Ravikumar Tulugu

Reputation: 1722

qsocketnotifier fires activated signal continuously even when there is 0 data on socket

I am trying to use qsocketnotifier with a TCP socket, the problem is that qsocketnotifier continously fires the "activated" signal even when there is no data to read on the socket. I have tried this on the socket both in "blocking " and "non blocking " mode. the behavior is same. did any body see this any time ? i am pasting the code piece below.

 QSocketNotifier *notifier = new QSocketNotifier(gwSocketId, QSocketNotifier::Read, this);
    connect(notifier, SIGNAL(activated(int)), this, SLOT(processClientEvents()));

Upvotes: 1

Views: 3541

Answers (2)

Zdenik
Zdenik

Reputation: 526

I was having the same problem using a QSocketNotifier + QTextStream to read from stdin. If multiple lines were sent to the app with one write I would get more QSocketNotifier::activated() signals than there were lines to read. Resulting in one extra QTextStream::readLine() call which would block, causing event processing in my app to come to a halt until I sent another line.

I tried using QTextStream::readAll but that always blocks until the end of file, making the problem occur on the very first QSocketNotifier::activated() signal.

After going around around with this trying to figure out how to tell whether there was actually any data to read from stdin before going into the blocking QTextStream::readLine() call, I finally just stopped using QTextStream and used fgets() instead. This seems to have solved my problem.

Here's some example code (not tuned to handle really large lines, that's an exercise for the reader). Hopefully this will save someone out there the headaches I went through trying to figure this out. I've thrown in some extra signal/event processing because that's a sure way to know if you've gone into a blocked state.

Example StdinReader header:

#include <QCoreApplication>
#include <QSocketNotifier>
#include <QTimer>
#include <cstdio>

class StdinReader : public QObject
{
  Q_OBJECT

public:
  StdinReader(QObject* parent = 0)
    : QObject(parent),
      notifier(new QSocketNotifier(fileno(stdin), QSocketNotifier::Read, this))
  {
    connect(this, SIGNAL(sigOutputData(QString)), SLOT(outputData(QString)));
    connect(notifier, SIGNAL(activated(int)), SLOT(consumeData()));
    notifier->setEnabled(true);
    QTimer::singleShot(1000, this, SLOT(timerTick()));
  }

  ~StdinReader() { }

signals:
  void sigOutputData(QString);

private slots:
  void outputData(QString data)
  {
    fprintf(stdout, "Data: %s\n", data.trimmed().toUtf8().constData());
    fflush(stdout);
  }

  void timerTick()
  {
    emit sigOutputData(QString::fromUtf8("tick"));
    QTimer::singleShot(1000, this, SLOT(timerTick()));
  }

  void consumeData()
  {
    notifier->setEnabled(false);

    fprintf(stdout, "Reading\n");
    fflush(stdout);

    char sbuf[8192];
    if (!fgets(sbuf, sizeof(sbuf), stdin)) {
      fprintf(stdout, "EOF\n");
      fflush(stdout);
      QCoreApplication::exit();
      return;
    }

    emit sigOutputData(QString::fromUtf8(sbuf));

    notifier->setEnabled(true);
  }

private:
  QSocketNotifier* notifier;
};

Example main()

int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);
  new StdinReader(&a);
  return a.exec();
}

Upvotes: 1

sam-w
sam-w

Reputation: 7687

From the QSocketNotifier docs:

Although the class is called QSocketNotifier, it is normally used for other types of devices than sockets. QTcpSocket and QUdpSocket provide notification through signals, so there is normally no need to use a QSocketNotifier on them.

QTcpSocket inherits from QIODevice, and hence has the signal readyRead(). I think this signal is what you're after.

Upvotes: 4

Related Questions