GNU screen是如何实际工作的?

4

我一直在尝试寻找关于GNU screen如何运作的高级信息,但不想阅读源代码,但我无法找到相关内容。

screen是如何做到即使在终端会话关闭后仍然存在的呢?它是否像守护进程一样运行,每个调用screen的人只是连接到它,然后它找到要附加的伪终端会话,还是它完全执行不同的操作?


1
你知道vncserver是如何工作的吗?基本上它与X服务器和像素不同,而是使用pty和文本。每个新的屏幕会话都作为后台进程运行,并且客户端可以通过/var/run/screen中的FIFO连接到它。 - that other guy
2个回答

6

这个问题有很多潜在的问题,所以我只会集中在一个问题上:

screen是如何做到即使终端会话关闭也能继续运行的?

Screen捕捉HUP信号,因此当其控制终端关闭时,它不会自动退出。相反,当它收到HUP信号后,它进入后台模式(因为它没有实际终端连接),并等待。当您使用各种-d/-D/-r/-R/-RR选项启动screen时,它会寻找已经运行的screen进程(可能在接收到HUP后分离,并/或通过发送HUP直接分离它),并接管该screen进程的子终端会话(一种合作过程,旧的screen进程将所有主PTY发送给新进程进行管理,然后退出)。


4

我没有深入研究过Screen本身,但我写了一个受它启发的程序,可以描述一下我的程序如何工作:

这个项目是我的终端模拟器,它有一个仿真核心、一个GUI前端、一个终端前端和两个类似于Screen的组件:attach.d和detachable.d。

https://github.com/adamdruppe/terminal-emulator

attach.d是前端。它通过Unix域套接字连接到特定的终端,并将活动屏幕的输出转发到实际终端。它还向后端进程发送消息,告诉它要从头开始重绘以及其他一些事情(还有更多的功能尚未完善)。

https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d

我的terminal.d库提供了一个事件循环,用于转换终端输入和信号。其中之一是HUP信号,当控制终端关闭时发送。当它看到这个信号时,前端附加进程关闭,而后端进程仍然存在。

https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d#L709

当Attach启动并无法连接到现有进程时,它会进行分叉并创建可分离的后端。

https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d#L454

通过将前端和后端分离成独立的进程,关闭其中一个不会影响另一个。screen 也是这样做的:运行 ps aux | grep -i screen。全大写的 SCREEN 进程是后端,小写的 screen 进程是前端。
me        3479  0.0  0.0  26564  1416 pts/14   S+   19:01   0:00 screen 
root      3480  0.0  0.0  26716  1528 ?        Ss   19:01   0:00 SCREEN  

我刚刚启动了screen,你可以看到两个独立的进程。screen分叉并创建了SCREEN,它实际上保存了状态。分离会终止进程3479,但保留进程3480。

我的后端是一个完整的终端仿真器,维护所有内部状态:

https://github.com/adamdruppe/terminal-emulator/blob/master/detachable.d

这里:https://github.com/adamdruppe/terminal-emulator/blob/master/detachable.d#L140 读取与附加程序通信的套接字中的消息,并将其作为终端输入转发给应用程序。
重新绘制方法,这里:https://github.com/adamdruppe/terminal-emulator/blob/master/detachable.d#L318 循环遍历其内部屏幕缓冲区 - 存储为属性和字符的数组 - 并将它们写回到所连接的终端。
你可以看到,这两个源文件并不是很长——大部分工作都是在终端仿真器核心中完成的。https://github.com/adamdruppe/terminal-emulator/blob/master/terminalemulator.d 而且,在某种程度上,我的终端客户端库(类似于定制的ncurses lib)也起了一些作用。https://github.com/adamdruppe/arsd/blob/master/terminal.d Attach.d还可以看到管理多个连接,使用select循环遍历每个打开的套接字,并仅绘制活动屏幕:https://github.com/adamdruppe/terminal-emulator/blob/master/attach.d#L300 我的程序为每个单独的终端屏幕运行一个独立的后端进程。GNU screen使用一个进程来处理整个会话,其中可能有多个屏幕。我猜想screen在后端做的工作比我多,但基本上是相同的原理:在每个pty上监视输入并更新内部屏幕缓冲区。当您运行screen -r以连接它时,它通过命名管道连接 - 文件系统中的FIFO(在我的gnu screen配置中,它们存储在/tmp/screens中),而不是我使用的unix套接字,但原理相同 - 它获取状态转储到屏幕,然后继续来回转发信息。
无论如何,我被告知我的源代码比screens和xterm更易于阅读,虽然不完全相同,但它们是相似的,所以您可以浏览它们以获得更多想法。

虽然很有趣,但这不是一个答案,因此超出了SO的问答格式。 - Alexander Gonchiy
1
问题是“屏幕如何工作”。答案与我上面描述的非常相似。就像有人问“bash如何工作”,然后有人编写了一个关于如何编写shell的教程。这并不完全是bash的工作方式(要了解它,您可以查看其自己的源代码),但它非常相似,并提供了使实际源代码更易读的解释。 - Adam D. Ruppe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接