使用QTextStream以非阻塞方式读取stdin

时间:2009-08-13 12:52:01

标签: c++ qt stdin blocking

使用Qt,我试图以非阻塞的方式读取stdin流的内容。当套接字收到一些新数据时,我正在使用QSocketNotifier来提醒我。通知程序的设置如下所示:

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

onData()广告位如下所示:

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;
}

正如您所看到的,我正在尝试使用select()系统调用来告诉我何时我的数据用完了。但是,在实践中发生的事情是,在我读完第一行文本后,select()调用返回0。因此,例如,如果我向进程的stdin流写入5行文本,我只读过第一行。

可能是什么问题?

2 个答案:

答案 0 :(得分:4)

线路缓冲。

默认是在“\ n”之后刷新。如果您在进程中写入5行,则会调用您的插槽5次。如果你想避免这种情况,你必须调用setbuf(stdin,_IOFBF)。但即便如此,也不能保证你可以在一个块中读取任意大量的数据。

编辑:最好使用QTextStream :: atEnd()而不是select,因为QTextStream有自己的内部缓冲区。

答案 1 :(得分:1)

我在其他答案中找到的例子几乎适合这个问题并且代码完整而简单:

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

我用它来实现一个基于QT控制台的应用程序,带有文本菜单,可以选择用户选择。