Ich habe ein Gerät, das Informationen über USB an meinen Computer sendet. Arch Linux richtet dieses Gerät ein, indem es eine Datei mit dem Namen erstellt ttyUSB0
. /dev/
Ich habe verwendet, GTKterm
um diese eingehenden Informationen zu empfangen und in einem emulierten Terminalfenster anzuzeigen.
Meine Frage ist, wie genau funktioniert GTKterm
das Lesen/Schreiben in diese ttyUSB0
Datei und wo kann ich anfangen zu lernen, wie man ähnliche Funktionen implementiert? Das heißt, in der einfachsten Form, wie kann ich ein Zeichen in schreiben ttyUSB0
oder im Gegensatz dazu ein Byte empfangen und in eine Datei schreiben?
Antwort1
TTYs sind Dateien, die Sie wie alle anderen verwenden können. Sie können sie mit den Standard-Dateiöffnungstools Ihrer Sprache öffnen und darin lesen oder schreiben. Sie haben ein spezielles Verhalten, das sich von dem „normaler“ Dateien unterscheidet, aber die Grundlagen sind dieselben. Ich werde am Ende auf einige der Sonderfälle eingehen, aber zuerst ein Experiment.
Eine interessante Sache, die Sie direkt von einem normalen Terminal aus tun können. Führen Sie es aus tty
und es wird eine Zeile wie diese ausgeben:
/dev/pts/2
Das ist das TTY-Gerät, auf dem Ihr Terminal läuft. Sie können etwas an dieses Terminal schreiben:
$ echo Hello > /dev/pts/2
Hello
$
Man kann sogar daraus lesen:
$ read X < /dev/pts/2
hello
$ echo $X
hello
$
( read X
ist der sh-Befehl „Lies eine Zeile von der Standardeingabe in die Variable X“; das < bedeutet, dass /dev/pts/2 als Standardeingabe für den Lesebefehl verwendet wird; das erste „Hallo“ habe ich eingegeben und das zweite wurde ausgedruckt).
Wenn Sie eine andere Shell öffnen, beispielsweise mit screen
oder xterm
, können Sie in dieser Shell run ausführen echo spooky > /dev/pts/2
, damit der Text auf Ihrem ursprünglichen Terminal angezeigt wird. Das Gleiche gilt für die anderen Befehle. Dabei öffnet Ihre Shell lediglich eine Datei, ohne zu wissen, dass es sich um ein TTY handelt.
Hier ist ein sehr einfaches C-Programm, das genau das tut, worum Sie gebeten haben. Es schreibt ein einzelnes Zeichen in /dev/pts/3 und liest dann ein einzelnes Byte daraus zurück:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
char byte;
int fd = open("/dev/pts/3", O_RDWR);
write(fd, "X", 1);
ssize_t size = read(fd, &byte, 1);
printf("Read byte %c\n", byte);
return 0;
}
Ein echtes TTY-Gerät, das an eine Shell oder einen Terminalemulator angeschlossen ist, wird dort ein interessantes Verhalten zeigen, aber Sie sollten etwas zurückbekommen.
Um auf ein Terminal zuzugreifen, müssen Sie die Berechtigung haben, es zu verwenden. Dies sind nur die Standarddateiberechtigungen, die Sie mit sehen ls -l
und mit festlegen chmod
: Sie benötigen Leseberechtigung, um die Datei zu öffnen und zu lesen, und Schreibberechtigung, um in sie zu schreiben. Die TTYs, die Ihr Terminal unterstützen, gehören Ihnen, die TTYs anderer Benutzer jedoch nicht, und TTYs für USB-Geräte können Ihnen gehören oder nicht, je nach Ihrer Konfiguration. Sie können die Berechtigungen auf die gleiche Weise wie immer ändern.
Um ein Programm zu schreiben, das damit arbeitet, müssen Sie nicht viel Besonderes tun. Sie können im Beispiel sehen, dass SienichtSie müssen die Datei jedes Mal schließen, damit Ihre Daten am anderen Ende gelesen werden: Die TTY-Dateien fungieren als Pipelines und übertragen die Daten in beide Richtungen, sobald sie eingehen. Als ich Text in das TTY schrieb, erschien er sofort, und als ich ihn anschließend las, wartete noch nichts auf mich. Es istnichtwie beim Schreiben in eine normale Datei, wobei die Daten auf der Festplatte gespeichert werden – sie werden sofort an die andere Seite weitergegeben oder im Speicher abgelegt, bis sie jemand liest.
Sie können diewählenFunktion, sodass Sie andere Dinge tun können, während Sie darauf warten, dass das Gerät etwas sagt. Wenn Sie jedoch zufrieden damit sind, einfach auf das Eintreffen der Daten zu warten, können Sie einfach blockierende Lesevorgänge verwenden und die Arbeit dem Betriebssystem überlassen.
Man sollte bedenken, dass die Puffergröße im Kernel begrenzt sein kann. Wenn man viele Daten auf einmal schreibt, kann es zu unbeabsichtigten Blockaden kommen. Wenn das wahrscheinlich ein Problem darstellt, verwenden Sienicht blockierende IOmit open("/dev/...", O_RDWR | O_NONBLOCK)
. Das Prinzip ist in beiden Fällen dasselbe.