web-dev-qa-db-ja.com

tty *デバイスの読み取り/書き込み方法は?

USB経由でコンピューターに情報を送信するデバイスを持っています。 Arch Linuxは、ttyUSB0/dev/という名前のファイルを作成して、このデバイスをセットアップします。私はGTKtermを使用して、この着信情報を受け取り、エミュレートされたターミナルウィンドウに表示しています。

私の質問は、GTKtermがこのttyUSB0ファイルをどのように正確に読み取り/書き込みするか、そして同様の機能を実装する方法をどこから学べるかです。つまり、最も基本的な形式では、どのように文字をttyUSB0に書き込むか、それとも、バイトを受け取ってファイルに書き込むのでしょうか。

35
sherrellbc

TTYは、他のファイルと同じように使用できるファイルです。あなたはあなたの言語の標準的なファイルを開くツールでそれらを開き、それらから読み書きすることができます。 「通常の」ファイルとは異なるいくつかの特別な動作がありますが、基本は同じです。最後にいくつかの特殊なケースについて説明しますが、最初に実験を行います。

通常のターミナルから直接実行できる興味深いことの1つ。 ttyを実行すると、次のような行が出力されます。

_/dev/pts/2
_

これは、端末が実行されているTTYデバイスです。その端末に何かを書き込むことができます。

_$ echo Hello > /dev/pts/2
Hello
$
_

あなたはそれから読むことさえできます:

_$ read X < /dev/pts/2
hello
$ echo $X
hello
$
_

(_read X_はshの「標準入力から変数Xへの行の読み取り」コマンドです。<は、読み取りコマンドの標準入力として/ dev/pts/2を使用することです。最初に入力した「hello」と、 2番目が印刷されました)。

screenまたはxtermを使用して別のシェルを開いた場合、そのシェルでrun _echo spooky > /dev/pts/2_を実行して、元のターミナルにテキストを表示できます。他のコマンド。これはすべて、TTYであることに気付かずにシェルがファイルを開くだけです。


これは、要求したことを実行し、/ dev/pts/3に単一の文字を書き込み、それから1バイトを読み取る非常に単純なCプログラムです。

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

シェルまたはターミナルエミュレーターに接続されている実際のTTYデバイスは、そこで興味深い動作をしますが、何かを取り戻す必要があります。


端末にアクセスするには、その端末を使用する権限が必要です。これらは、_ls -l_で表示され、chmodで設定される標準のファイル権限です。ファイルを開いて読み取るには読み取り権限が必要であり、ファイルに書き込むには書き込み権限が必要です。端末をサポートするTTYはあなたが所有しますが、別のユーザーのTTYは所有せず、USBデバイスのTTYは構成によって異なる場合があります。通常と同じ方法で権限を変更できます。

それを扱うプログラムを書く限り、特別なことをする必要はありません。この例では、してはいけない必要なことの1つは、ファイルを毎回閉じて、もう一方の端でデータを読み取らせることです。 TTYファイルはパイプラインのように機能し、データを双方向にプッシュするだけです。TTYにテキストを書き込んだとき、すぐに表示され、その後それを読んだとき、何も待っていませんでした。これは、データがディスクに保存される通常のファイルに書き込むようなではないです-反対側にすぐに渡されるか、誰かにメモリに保存されますそれを読みます。

select 関数を使用して、デバイスが何かを言うのを待つ間、他のことを行うことができますが、データが届くのを待つだけでよければ、読み取りをブロックし、OSに解除を実行させます。

心に留めておくべきことの1つは、カーネル内のバッファーサイズが制限されている可能性があることです。一度に大量のデータを書き込むと、意味のないままブロックされる可能性があります。それが問題になる可能性がある場合は、open("/dev/...", O_RDWR | O_NONBLOCK)とともに non-blocking IO を使用します。原理はどちらの方法でも同じです。

43
Michael Homer