Wie implementiert man ein Timeout im read() Funktionsaufruf?
Lesezeit: 5 Minuten
domlao
Ich möchte den seriellen COM-Port für die Kommunikation verwenden und jedes Mal, wenn ich den anrufe, ein Timeout implementieren lesen() Funktionsaufruf.
int filedesc = open( "dev/ttyS0", O_RDWR );
read( filedesc, buff, len );
BEARBEITEN:
Ich verwende Linux OS. Wie implementiert man den Select-Funktionsaufruf?
select() benötigt 5 Parameter, zuerst den höchsten Dateideskriptor + 1, dann ein fd_set zum Lesen, eines zum Schreiben und eines für Ausnahmen. Der letzte Parameter ist ein Struktur-Zeitwert, der für die Zeitüberschreitung verwendet wird. Es gibt -1 bei einem Fehler, 0 bei Zeitüberschreitung oder die Anzahl der Dateideskriptoren in den festgelegten Sätzen zurück.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
int main(void)
{
fd_set set;
struct timeval timeout;
int rv;
char buff[100];
int len = 100;
int filedesc = open( "dev/ttyS0", O_RDWR );
FD_ZERO(&set); /* clear the set */
FD_SET(filedesc, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
rv = select(filedesc + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
printf("timeout"); /* a timeout occured */
else
read( filedesc, buff, len ); /* there was data to read */
close(filedesc);
}
Diese Lösung ist nicht gut genug, denn wenn wir auf 5 Bytes warten, aber rechtzeitig nur 1 erhalten, ist die Auswahl damit in Ordnung und wir werden beim Lesen für immer blockieren.
– Roskoto
28. September 2012 um 13:05 Uhr
Nein würde es nicht. Wenn nur ein Byte verfügbar wäre und Sie versuchen, 5 zu lesen, würde read() nicht blockieren, sondern 1 zurückgeben (Anzahl der gelesenen Bytes). Aus der Read-Manpage: „Es ist kein Fehler, wenn diese Zahl kleiner als die Anzahl der angeforderten Bytes ist; dies kann beispielsweise passieren, weil derzeit tatsächlich weniger Bytes verfügbar sind (vielleicht weil wir uns dem Ende der Datei näherten , oder weil wir von einer Pipe oder von einem Terminal lesen) oder weil read() durch ein Signal unterbrochen wurde.”
– Puppe
10. Oktober 2012 um 7:09 Uhr
und wie man immer wieder “auswählt”, das zweite Mal wird sofort zurückkehren. Ich will wissen warum?
– Känguru
1. Februar 2015 um 4:02 Uhr
@kangear siehe man select und es wird erklärt timeval Timeout-Funktion. Kurz gesagt, heißt es “Betrachten Sie das Timeout als undefiniert, nachdem select() zurückkehrt.” und das bedeutet, dass Sie es nicht wiederverwenden sollten, wenn Sie nicht wirklich sicher sind, was (und wo) Sie tun.
– Sampo Sarrala – codidact.org
18. Oktober 2015 um 16:37 Uhr
Das ursprüngliche Poster gab an, dass er Linux ausführte, und die Frage ist mit Linux markiert, also habe ich eine Antwort gegeben, die unter Linux funktioniert.
– Puppe
31. Januar 2017 um 5:54 Uhr
Café
Als Alternative zu select()für den speziellen Fall einer seriellen Schnittstelle (Terminal), die Sie verwenden können tcsetattr() um den Dateideskriptor mit einem Lese-Timeout in den nicht-kanonischen Modus zu versetzen.
Deaktivieren Sie dazu die ICANON Flag, und setzen Sie die VTIME Steuerzeichen:
struct termios termios;
tcgetattr(filedesc, &termios);
termios.c_lflag &= ~ICANON; /* Set non-canonical mode */
termios.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */
tcsetattr(filedesc, TCSANOW, &termios);
Notiz VTIME in Zehntelsekunden gemessen wird und dass der dafür verwendete Typ typischerweise ein ist unsigned charwas bedeutet, dass das maximale Timeout 25,5 Sekunden beträgt.
In meinem Fall musste ich auch VMIN auf 0 setzen: termios.c_cc[VMIN] = 0.
– João MS Silva
4. Dezember 2014 um 22:28 Uhr
Angenommen, wir haben zwei Geräte TxDev und RxDev, die bei t = T1 über UART kommunizieren, TxDev beginnt, Daten zu senden, zu diesem Zeitpunkt erreicht RxDev die Leseanweisung noch nicht, gehen die ersten von TxDev gesendeten Bytes verloren?, oder RxDev hat Ein Puffer, in dem empfangene Daten gespeichert werden, wird nicht aufgerufen ?
– Fed
1. Juli 2016 um 8:03 Uhr
@fedi: Unter Linux werden sie vom Kernel gepuffert.
– Café
1. Juli 2016 um 12:37 Uhr
Wenn Sie den Socket so einstellen, dass er im nicht blockierenden Modus betrieben wird, liest jeder Aufruf von read nur die aktuell verfügbaren Daten (falls vorhanden). Dies ist also effektiv gleichbedeutend mit einem sofortigen Timeout.
Sie können den nicht blockierenden Modus für einen Socket mit einer Funktion wie der folgenden festlegen:
int setnonblock(int sock) {
int flags;
flags = fcntl(sock, F_GETFL, 0);
if (-1 == flags)
return -1;
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
(Weitere Informationen zum Lesen von nicht blockierenden Sockets finden Sie in der read Manpage)
Sie sagen nicht, was das Betriebssystem ist, aber wenn Sie unter Linux laufen, könnten Sie den select-Aufruf verwenden. Es kehrt zurück, wenn im Dateideskriptor etwas zu lesen ist, oder Sie können es so einrichten, dass es abläuft, wenn nichts zu lesen ist. Der Rückgabecode gibt an, welche.
Rick-Rick-Rick
Der folgende Code verwendet Millisekunden-Timeouts pro Zeichen. Ich verwende es in einem meiner Projekte, um vom COM-Port zu lesen.
Sehen linux.die.net/man/2/select
– sizzzzlerz
27. Mai 2010 um 1:29 Uhr