views:

720

answers:

1

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?

A: 

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.

drhirsch
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