Socat und Rich Terminal wieder

780
ilya

Ich fange socatan einem Terminal mit der Ausführung ansocat - UNIX-listen:/tmp/sock

Dann gehe ich zu einem anderen Terminal und starte ein Programm (per Python) so, dass es im ersten Terminal zu laufen scheint. Hier ein Beispiel:

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() 

Programme mit einfacher Eingabe / Ausgabe wie "cat" funktionieren gut, aber komplexere (wie "vim" oder "bash") sind offensichtlich nicht sehr glücklich. Abgesehen davon, wenn ich Cntrl-Cdas erste Terminal anschlage, wird das socatgetötet, während ich es vorziehen würde, dass der Tastatur-Interrupt an das prgProgramm geliefert wird (im Python-Code oben gestartet).

Meine Frage ist: Wenn es möglich ist und wie man es sagen soll socat, verhält es sich wie der prgBesitzer des Terminals und nicht sich socatselbst.

PS. Es könnte scheinen, dass diese Frage ein Duplikat ist dies ein, aber es ist nicht der Fall, weil in dieser Frage die prgdirekt aufgerufen wird socat, so ist es möglich, verwenden EXECOptionen.

2

1 Antwort auf die Frage

2
grawity

Signale oder Besitzstände können nicht "magisch" über eine Steckdose übertragen werden.

Über AF_UNIX können Sie den tty-Dateideskriptor selbst senden (mithilfe von sendmsg und recvmsg) und die empfangende Seite (und nicht den Socket) als stdout / stderr des Unterprozesses verwenden. Dies ist nicht mit plain socat möglich, aber diese Methode wird intern von zB dem Tool tmux verwendet.


Bei plain socat können Sie am besten ein 0x03-Byte (^ C) senden, wenn Sie Strg + C drücken (dies ist die Aufgabe von Telnet und ssh). Sie können dies testen, indem Sie drücken Ctrl+VCtrl+C, um es einmal zu senden, oder indem Sie stty rawvor socat laufen, um dauerhaft in den "Rohmodus" zu wechseln.

Das reicht jedoch nicht aus, um das Tastendruck zu verstehen . Die grundlegendste Methode wäre, jedes Byte manuell zu prüfen. SIGINT senden, wenn 0x03 angezeigt wird. Schreiben Sie es sonst in den Standardprozess des Unterprozesses.

Was jedoch telnetd und sshd tun, ist das Hinzufügen einer 'Pseudo-tty' zwischen Socket und Subprozess. In Python können Sie eine erstellen os.openpty(). Die 'Slave'-Seite muss als stdout / stderr des Unterprozesses angegeben werden, und Ihr Skript muss in einer Schleife ausgeführt werden, um Daten zwischen dem Socket und der' Master'-Seite zu kopieren.

Das ist immer noch nicht ganz genug - ein voll ausgestattete Terminal - Login - Protokoll, wie zum Beispiel SSH oder Telnet, würde auch Nachrichten hat die PTYs Dimensionen zu aktualisieren, und reagiert auf termios Einstellungsänderungen (zB die „lokales Echo“ -Einstellung und andere gesehen in stty).

Es wäre nützlich, den Quellcode des Telnet-Clients und des Telnetd-Servers, z. B. von GNU-Inetutils, zu lesen, da sie genau dies tun.

Danke für die Antwort! Leider ist es nicht so einfach, wie ich gehofft hatte. Kann es sein, dass mein Problem leichter zu lösen ist, wenn ich es weniger allgemein formuliere? Was ich erreichen möchte, ist folgendes: Ich habe ein "main" Python-Programm, das ein neues Fenster in einer gegebenen tmux-Sitzung öffnet und ein anderes Programm "xxx" in diesem neuen Fenster startet, aber der Python-Hauptprozess muss die volle Kontrolle darüber haben ("xxx" muss also eine "Subprozess" -Instanz oder eine ähnliche Instanz sein). Also bitte ich libtmux, ein neues Fenster mit window_shell = "socat - UNIX-listen: / tmp / sock" zu öffnen und dann wie in der obigen Frage beschrieben eine Verbindung herzustellen. Wird das helfen? ilya vor 8 Jahren 0
Könnten Sie libtmux bitten, Ihnen nur den pty-Namen des Fensters oder fd direkt anzugeben? grawity vor 8 Jahren 0
Ja, nachdem ich ein tmux ** -Fenster ** erstellt habe, sehe ich in `window.panes [0] ['pane_tty']` einen Pseudo-tty-Gerätenamen, zum Beispiel `/ dev / pts / 57 ' ilya vor 8 Jahren 0
Könnten Sie bitte Ihre Antwort etwas ausarbeiten: nachdem ich `(master, slave) = os.openpty ()` aufgerufen habe und dann `subprocess.Popen (stdout = slave, stderr = slave ....)` anrufe, was soll ich geben als `stdin`-Parameter? Ist es eine gute Idee, `/ dev / pts / XXX` direkt zu öffnen und den Deskriptor als` stdin` an `subprocess.Popen (...)` zu übergeben? Und die zweite Frage: Was versteht man unter Kopieren von Daten zwischen dem Socket und der "Masterseite"? Wo genau soll ich lesen und wo schreiben? ilya vor 8 Jahren 0
Der pty-Slave wird sowohl als Eingang _ als auch als Ausgang für den Unterprozess verwendet. Ebenso muss der pty-Master von _und_ in den Socket kopiert werden. (Möglicherweise benötigen Sie select.poll () oder einen ähnlichen Eventloop.) grawity vor 8 Jahren 0
Nochmals vielen Dank für die Klarstellung. Ich habe dieses Beispielskript (http://pastebin.com/gfD3gGtw) mit Ihren Vorschlägen geschrieben. Auf der Terminalseite starte ich socat mit dem folgenden Befehl: `socat-Datei: $ (tty), raw, echo = 0 UNIX-listen: / tmp / blah-socket 'und auf der Python-Seite starte ich das Skript einfach mit Argumente, die angeben, welches Programm gestartet werden soll. Ich habe "cat" und "vim" ausprobiert und beide funktionieren gut. Wenn Sie Kommentare zum Skript haben, zögern Sie bitte nicht, einen Kommentar abzugeben. ilya vor 8 Jahren 0