2010-10-05 14 views
6

Come si legge un FIFO/named pipe per linea da un'app C++/Qt Linux?Come si legge un FIFO/named pipe line by line da un'app C++/Qt Linux?

Oggi posso aprire e leggere da un fifo da un programma Qt, ma non riesco a ottenere il programma per leggere i dati riga per riga. Qt legge l'intero file, il che significa che aspetta che il "mittente" chiuda la sua sessione.

Facciamo un esempio con alcuni comandi della shell per mostrare cosa vorrei fare l'app.

Innanzitutto creare una FIFO

mkfifo MyPipe 

Poi possiamo usare cat per leggere dal FIFO

cat MyPipe 

E poi mandiamo alcuni dati con un altro gatto

cat > MyPipe 

E quindi inizia a digitare qualcosa, e ogni volta che premi entri, arriva al lettore. E poi quando lo chiudi con Ctrl + D entrambi i lati finiscono.

Ora il mittente è facile da creare con QTextStream, , è sufficiente svuotare quando si desidera inviare.

QFile file("MyPipe"); 
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) 
    return; 

QTextStream out(&file); 
for(int i=0; i<3; i++) { 
    out << "Hello...: " << i << "\n"; 
    out.flush(); 
    sleep(2); 
} 

file.close(); 

Ma poi di scrivere un piccolo lettore che leggere riga per riga è dove mi sono bloccato in questo momento, tutti i miei tentativi con la lib Qt finisce con che ottengo i dati, ma non fino il mittente usa file.close() sulla fifo. Non quando arrossisce, come succede quando uso cat per leggere.

come in questo esempio:

QFile file("MyPipe"); 
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) 
    return 0; 

QTextStream in(&file); 
QString line; 
do { 
    line = in.readLine(); 
    qDebug() << line; 
} while (!in.atEnd()); 


file.close(); 

Che cosa mi manca?

Si sente proprio come ho bisogno di utilizzare una sorta di isReady o lineAvailable sul torrente o qualcosa di simile, ma non riesco a trovare nulla nella documentazione che si adatta ...

/Grazie


Nota:

Se vado con il c stile a basso livello e letto un carattere al tempo che faccio otteniate Im mare stile cazzeggio per. Ma sarebbe bello poter fare lo stesso stile Qt.

FILE *fp; 
fp=fopen("MyPipe", "r"); 
char c; 
while((c=getc(fp)) != EOF) 
{ 
    printf("%c",c); 
} 
fclose(fp); 

Aggiornamento:

Quando inizio un debugger il programma è appesa al readLine(), e non continuare fino a quando l'altra parte chiude il FIFO.

E io capisco lo stesso con ">>"

line = in.readLine(); 
    in >> line; 
+1

Potrebbe essere che la pipe viene letta immediatamente, e in realtà è l'output dello schermo che viene bufferizzato? Hai usato 'qDebug() << line;' e non vedo alcun flushing. –

+0

Buon punto, non ci ho pensato. – Johan

risposta

4

Utilizzare lo stile di basso livello c e leggere un carattere alla volta.

FILE *fp; 
fp=fopen("MyPipe", "r"); 
char c; 
while((c=getc(fp)) != EOF) 
{ 
    printf("%c",c); 
} 
fclose(fp); 
+0

'c' deve essere' int' altrimenti potrebbe essere un ciclo infinito se 'char' non è firmato (' EOF' è intero negativo ('-1' tipicamente)). – jfs

2

Non so che cosa non funziona, ma si può provare a eseguire il debug usando strace:

strace -o writer.log -e trace=write ./writer 
strace -o reader.log -e trace=read ./reader 

La prima linea registrerà tutte le chiamate di sistema scritte effettuate dal programma di scrittura. La seconda linea funziona in modo simile. In questo modo è possibile tracciare la chiamata di sistema e accertarsi che lo svuotamento funzioni.

Se vedi la chiamata ripetuta da leggere, con i tempi e i dati corretti, allora hai un problema con QTextStream.

Cosa succede se non si usa QTextStream, ma si legge direttamente dal file?

+0

strace è bello, e ho avviato un "watch tail reader.log" in un'altra finestra e posso vedere che ottiene i dati che gli ho inviato. – Johan

+0

@Johan: sei sicuro che il problema sia dal lato del lettore? – shodanex

+0

95% sicuro perché se sostituisco la "versione Qt" con la "versione C" funziona. – Johan

1

Si potrebbe provare ad aprire il file sul lato lettore con il flag QIODevice::Unbuffered.

+1

Idea di Dio, ma è sempre la stessa :( – Johan

2
if(file.bytesAvailable()) 
QString line = file.readLine(); 

Si potrebbe usare qualcosa di simile.

+0

L'implementazione QFile dei byte disponibili NON FUNZIONA per i file speciali, compresi i named pipe, e infatti blocca l'applicazione! –