为什么远程终端在退出时挂起?

为什么远程终端在退出时挂起?

我写了一个远程 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 命令并且没有在远程会话中运行任何外部程序。

编辑

精确定义什么是外部程序有点困难。我有一种感觉,如果程序没有“守护进程”,那么它被认为是“内部”。即,如果我运行lscpvi,那就没问题,但如果我运行一个服务程序,&在命令行末尾使用,那么rt将在退出时挂起。


我做了一些研究,但不幸的是很难用一句话来描述这个问题。我能找到的最相关的资源是:

当终端模拟器退出时,为什么shell也退出?

我想如果我发送到某个地方可能会有所帮助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 输出缓冲中的异常情况。您会看到我上面提到的一些程序可以执行此操作。

相关内容