9

Using Qt, I'm attempting to read the contents of the stdin stream in a non-blocking fashion. I'm using the QSocketNotifier to alert me when the socket has recieved some new data. The setup for the notifier looks like this:

QSocketNotifier *pNot = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read, this);
connect(pNot, SIGNAL(activated(int)), this, SLOT(onData()));
pNot->setEnabled(true);

The onData() slot looks like this:

void CIPCListener::onData()
{
    qDebug() << Q_FUNC_INFO;
    QTextStream stream(stdin, QIODevice::ReadOnly);

    QString str;

    forever
    {
        fd_set stdinfd;
        FD_ZERO( &stdinfd );
        FD_SET( STDIN_FILENO, &stdinfd );
        struct timeval tv;
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        int ready = select( 1, &stdinfd, NULL, NULL, &tv );
        if( ready > 0 )
        {
            str += stream.readLine();
        }
        else
        {
            break;
        }
    }

    qDebug() << "Recieved data:" << str;
}

As you can see I'm attempting to use the select() system call to tell me when I've run out of data to read. However, in practise what is happening is the select() call returns 0 after I've read the first line of text. So, for example, if I write 5 lines of text to the process's stdin stream, I only ever read the first line.

What could be the problem?

Thomi
  • 11,647
  • 13
  • 72
  • 110
  • have you tried readAll instead of readLine? – Bob Aug 14 '09 at 10:17
  • yup. I think it uses atEnd() internally to detect when it's reached the end of the stream. The upshot is that it blocks forever. – Thomi Aug 14 '09 at 11:34
  • 1
    ok, only other thing i can think of trying is scrapping the current implementation (the select call) and doing something similar to what the assitant does, see tools\assistant\tools\assistant\remotecontrol* – Bob Aug 14 '09 at 12:48
  • This code is working fine when I input directly into the terminal. It's enough for me... Thanks. ;) – TCB13 Sep 04 '11 at 22:38

2 Answers2

4

Line buffering.

Default is flushing after a "\n". If you write 5 lines to your process, your slot gets called 5 times. If you want to avoid that, you have to call setbuf(stdin, _IOFBF). But even then it is not guaranteed you can read arbitrarily large amounts of data in one chunk.

Edit: It would probably better to use QTextStream::atEnd() instead of select, since QTextStream has its own internal buffers.

Gunther Piez
  • 29,760
  • 6
  • 71
  • 103
  • 1
    You cannot use QTextStream::atEnd() on stdin - the Qt documentation says so (look in the detailed documentation for the class). See: http://doc.trolltech.com/4.5/qtextstream.html#details – Thomi Aug 14 '09 at 07:09
1

I've found and example in other answer that fits almost to this question and with complete and simple code:

https://stackoverflow.com/a/7389622/721929

I've used it to implement a QT console based app with a textual menu to choose on user selection.

Community
  • 1
  • 1
kikeenrique
  • 2,589
  • 2
  • 25
  • 46