web-dev-qa-db-ja.com

再びsocatとリッチターミナル

socat - UNIX-listen:/tmp/sockを実行して、端末でsocatを起動します

次に、別のターミナルに移動し、最初のターミナルで実行されているように見えるように(pythonで)プログラムを起動します。例を次に示します。

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/sock")
proc=subprocess.Popen(['prg'], stdin=s, stdout=s, stderr=s, Shell=False)
proc.wait()

たとえば「cat」のような単純な入出力を備えたプログラムは正常に機能しますが、より複雑なプログラム(「vim」や「bash」など)は明らかにあまり満足していません。それ以外に、最初の端末でCntrl-Cを押すと、socatが強制終了されますが、キーボード割り込みをprgプログラム(pythonで開始)に配信することをお勧めします上記のコード)。

私の質問は、それが可能かどうか、そしてそれをsocatに伝えて、prgが端末の所有者であり、socat自体ではないように動作させる方法です。

PS。この質問は これ と重複しているように見えるかもしれませんが、そうではありません。その質問では、prgsocatによって直接呼び出されるため、EXECオプションを使用できます。

2
ilya

シグナルもttyの所有権も、ソケットを介して「魔法のように」運ぶことはできません。

AF_UNIXを介して、ttyファイル記述子自体を送信し( sendmsg およびrecvmsgを使用)、受信側にそれを使用させることができます(およびnotソケット)をサブプロセスのstdout/stderrとして使用します。これはプレーンなsocatでは実行できませんが、このメソッドは内部で使用されます。 tmuxツール。


プレーンなsocatを使用すると、Ctrl + Cが押されたときにリテラルの0x03バイト(^ C)を送信するようにすることができます(これがtelnetとsshの機能です)。を押すとこれをテストできます Ctrl+VCtrl+C 一度送信するか、socatの前に_stty raw_を実行して、永続的に「rawモード」に入ります。

ただし、受信側が実際にキーを押して理解するのに十分ではありません。最も基本的な方法は、各バイトを手動でチェックすることです。0x03が検出されたらSIGINTを送信します。それ以外の場合は、サブプロセスのstdinに書き込みます。

ただし、telnetdとsshdが行うことは、ソケットとサブプロセスの間に「pseudo-tty」を追加することです。Pythonでは、os.openpty();を使用して作成できます。スレーブ側はサブプロセスのstdout/stderrとして指定する必要があり、スクリプトはソケットとマスター側の間でデータをコピーするループで実行する必要があります。

それでもまだ十分ではありませんquite– SSHやTelnetなどのフル機能のターミナルログインプロトコルにも、ptyのサイズを更新して反応するメッセージがありますターミナル設定の変更(例:「ローカルエコー」設定およびsttyに表示されるその他の設定)。

Telnetクライアントとtelnetdサーバーのソースコードを読むと便利です。 from GNU inetutils、まさにそれを行うからです。

2
user1686