2009-08-13 8 views
7

En utilisant Qt, j'essaie de lire le contenu du flux stdin d'une manière non bloquante. J'utilise le QSocketNotifier pour m'avertir quand le socket a reçu de nouvelles données. La configuration du notificateur ressemble à ceci:en utilisant QTextStream pour lire stdin de manière non bloquante

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

L'emplacement onData() ressemble à ceci:

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

Comme vous pouvez le voir, je suis tenté d'utiliser l'appel système select() pour me dire quand Je n'ai plus de données à lire. Cependant, en pratique, ce qui se passe est que l'appel select() renvoie 0 après avoir lu la première ligne de texte. Ainsi, par exemple, si j'écris 5 lignes de texte dans le flux stdin du processus, je ne lis jamais que la première ligne.

Quel pourrait être le problème?

+0

Avez-vous essayé readAll au lieu de readLine? – Bob

+0

yup. Je pense qu'il utilise en interne atEnd() pour détecter quand il a atteint la fin du flux. Le résultat est qu'il bloque pour toujours. – Thomi

+1

ok, seulement une autre chose que je peux penser essayer est de mettre au rebut l'implémentation actuelle (l'appel select) et de faire quelque chose similaire à ce que fait l'assistant, voir tools \ assistant \ tools \ assistant \ remotecontrol – Bob

Répondre

4

Tampon de ligne.

La valeur par défaut est "rinçage" après un "\ n". Si vous écrivez 5 lignes à votre processus, votre emplacement est appelé 5 fois. Si vous voulez éviter cela, vous devez appeler setbuf (stdin, _IOFBF). Mais même alors, il n'est pas garanti que vous pouvez lire arbitrairement de grandes quantités de données dans un morceau.

Éditer: Il serait probablement préférable d'utiliser QTextStream :: atEnd() au lieu de select, puisque QTextStream a ses propres tampons internes.

+1

Vous ne pouvez pas utiliser QTextStream :: atEnd() sur stdin - la documentation de Qt le dit (regardez dans la documentation détaillée de la classe). Voir: http://doc.trolltech.com/4.5/qtextstream.html#details – Thomi

1

J'ai trouvé et par exemple dans un autre réponse qui correspond à peu près à cette question et avec le code complet et simple:

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

Je l'ai utilisé pour mettre en œuvre une application basée sur la console QT avec un texte menu à choisir sur la sélection de l'utilisateur.

Questions connexes