socat和富有的终端再次


2

socat通过执行来启动终端socat - UNIX-listen:/tmp/sock

然后我去另一个终端并以这样的方式启动程序(通过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的选项。

Answers:


2

信号或tty所有权不能通过套接字“神奇地”传输。

通过AF_UNIX,您可以发送tty文件描述符本身(使用sendmsg和recvmsg)并让接收方使用它(而不是套接字)作为子进程'stdout / stderr。这不能用普通的socat来完成,但是这种方法在内部由例如tmux工具使用。


使用普通的socat,你可以做的最多就是当按下Ctrl + C时它会发送一个文字0x03字节(^ C)(这就是telnet和ssh所做的)。您可以通过按Ctrl+VCtrl+C一次发送或stty raw在socat之前运行以永久进入“原始模式” 来测试此项。

但这并不足以让接收端真正了解按键。最基本的方法是手动检查每个字节 - 当它看到0x03时发送一个SIGINT; 否则将它写入子进程'stdin。

然而,telnetd和sshd做的是在套接字和子进程之间添加一个'伪tty' - 在Python中你可以创建一个使用os.openpty(); 'slave'一侧需要作为子进程'stdout / stderr给出,你的脚本需要在套接字和'master'端之间复制数据的循环中运行。

这仍然不是不够-一个全功能的终端登录协议,如SSH或Telnet,也有消息更新PTY的尺寸,并作出反应的termios设置更改(例如“本地回显”设置和其他人在看到stty)。

读取telnet客户端和telnetd服务器的源代码(例如来自GNU inetutils)将非常有用,因为他们正是这样做的。


谢谢你的回答!唉,这并不像我希望的那么容易。如果我以较不一般的风格制定它,我的问题会更容易解决吗?我想要实现的是:我有一个“主”python程序,它在给定的tmux会话中打开一个新窗口,并在这个新窗口中启动另一个程序“xxx”,但主python进程必须完全控制它(所以“xxx”必须是“子进程”实例或类似的)。所以首先我要求libtmux使用window_shell =“socat - UNIX-listen:/ tmp / sock”打开一个新窗口,然后按照上面的问题进行连接。这会有帮助吗?
ilya 2016年

你能问libtmux直接给你窗口的名字或fd吗?
grawity 2016年

是的,在我创建了一个tmux 窗口后,我可以看到window.panes[0]['pane_tty']一个伪tty设备名称,例如/dev/pts/57
ilya 2016年

你能不能详细说明你的答案:在我打电话(master, slave)=os.openpty()然后打电话给subprocess.Popen(stdout=slave, stderr=slave....)我应该作为stdin参数给出什么?它是开一个好主意,/dev/pts/XXX直接给出描述符stdinsubprocess.Popen(...)?第二个问题:在套接字和“主”端之间复制数据是什么意思?我应该从哪里读到以及在哪里写?
ilya 2016年

pty slave用作子进程的输入输出。同样地,pty主需要从复制套接字。(你可能需要select.poll()或类似的eventloop。)
grawity 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.