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。この質問は これ と重複しているように見えるかもしれませんが、そうではありません。その質問では、prg
はsocat
によって直接呼び出されるため、EXEC
オプションを使用できます。
シグナルも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、まさにそれを行うからです。