我写了一个远程 tty 工具(称为“rt”),其工作原理如下:
[rt client(rtc)] <---> [rt gateway(rtg)] <---> [rt server(rts)]
其中rts
是 NAT 防火墙后面的主机,它rt
在/etc/rc.local
其中运行,连接到rtg
.当我想连接到 rts 时,我在rtc
计算机上运行 rt,它连接到rtg
,然后将请求发送到rts
。该rt
程序将/usr/bin/login
在 TTY 中启动,从而在rtc
和之间创建一个远程终端rts
。
我的问题是,如果我在远程终端中运行一些命令,然后键入exit
退出 bash,我希望返回到本地终端提示符,但它几乎总是挂起并显示空白屏幕,除了如果我只是运行一些 bash 命令并且没有在远程会话中运行任何外部程序。
编辑:
精确定义什么是外部程序有点困难。我有一种感觉,如果程序没有“守护进程”,那么它被认为是“内部”。即,如果我运行ls
、cp
等vi
,那就没问题,但如果我运行一个服务程序,&
在命令行末尾使用,那么rt
将在退出时挂起。
我做了一些研究,但不幸的是很难用一句话来描述这个问题。我能找到的最相关的资源是:
我想如果我发送到某个地方可能会有所帮助SIGHUP
,但是如何发送呢?哪个程序是发送方,哪个程序是接收方?
答案1
您描述的行为是控制器软件的典型行为,它从 TTY 读取(即远程终端的输出),并继续读取(如果需要,则等待)直到获得 EOF。但是伪tty就像一个管道——读取进程不会得到EOF,直到所有打开它进行写入的进程都将其关闭。 (当进程退出时,会导致它关闭所有打开的文件。)
但是,除非您重定向标准输出和标准错误,否则异步进程会保持 tty 打开以作为 stdout 和 stderr 写入。虽然 nohup
的主要功能是忽略挂断 (HUP) 信号,但它的次要功能是确保 stdout 和 stderr 不指向 tty。如果您使用>
and (或其变体)重定向输出流2>
,那很好;nohup
会让他们独自一人。但是,如果您不重定向输出,nohup
请将其重定向到 nohup.out
. (可能有一些更复杂的微妙细节,但与这个问题无关。)
长话短说 如果您运行异步命令而不重定向 stdout 和 stderr(为了安全起见,还重定向 stdin),那么当您从 shell 退出时,您的rt
程序将不会退出,直到所有后台进程关闭其引用的文件描述符。蒂。实际上,这意味着它会等待后台进程退出。
在我看来,“简单明了”的解决方案是将程序修改为在子进程退出时退出。用户(即你)登录时得到的交互式shell进程
是同一个过程作为您启动的那个/usr/bin/login
。我希望你用fork()
and exec()
(或它的一些变体)来做这件事。因此,只需跟踪 PID 并调用wait()
(或其一些变体)即可。
笔记:
- 您需要使用多个进程或至少多个线程来等待 shell 退出,同时从伪 TTY 中并发读取。
- 有许多程序,例如
nc
(netcat
) 和sshd
,已经可以处理这种情况,并且我确信其中一些是开源的。您可以查看它们以获得一些想法(和一些代码)。 wait()
您可能需要考虑的一项功能是在终止前返回后休眠几秒钟rt
,以处理 TTY 输出缓冲中的异常情况。您会看到我上面提到的一些程序可以执行此操作。