这几天学习发现了一个很好玩的命令——screen。screen 是一个可以在多个进程之间复用一个物理终端的全屏窗口管理器,只要 screen 本身没有终止,其内部运行的会话都可以恢复,即使是网络中断。
有时候我们需要远程执行一些任务,如备份,开启的远程终端窗口在任务执行完毕之前不能关掉该窗口,否则任务进程会被杀掉。这时可以通过 screen 命令来同时连接多个本地或远程会话。并在其间自由切换。
会话恢复
两个远程终端窗口连接到同一服务器
窗口一
$ ssh pi@raspberrypi.id
窗口二
$ ssh pi@raspberrypi.id
窗口一执行耗时任务时中断
窗口一执行以下脚本,每隔一秒输出一个递增的数字。
$ i=0; while [ $i -lt 100 ]; do sleep 1; echo $i; i=`expr $i + 1`; done;
0
1
...
这时候,在窗口二查看进程,应该可以看到 sleep 进程。
$ ps aux | grep sleep
pi 3924 0.0 0.0 6456 376 pts/0 S+ 22:46 0:00 sleep 1
pi 3926 0.0 0.0 7348 584 pts/1 S+ 22:46 0:00 grep --color=auto sleep
接着关闭窗口一,再次在窗口二查看进程,发现 sleep 进程已经没有了。
$ ps aux | grep sleep
pi 3955 0.0 0.0 7348 580 pts/1 S+ 22:50 0:00 grep --color=auto sleep
打开新窗口(窗口三)开启 screen 会话后,再次执行耗时任务时中断
screen -S helloworld
命令创建了一个 socket 名为 helloworld 的会话。
$ ssh pi@raspberrypi.id
$ screen -S helloworld
$ i=0; while [ $i -lt 100 ]; do sleep 1; echo $i; i=`expr $i + 1`; done;
0
1
这时候,在窗品二查看进程,同样可以看到 sleep 进程。
关闭窗口三。
窗口二连接窗口三创建的 screen 会话
$ screen -x helloworld
0
1
2
3
4
5
6
...
可以看到窗口三之前的任务在继续执行。
远程协作(会话共享)
通过以上的操作,可以发现窗口二可以看到窗口三的完整任务,也就是会话在窗口二和窗口三之间实现了共享,窗口二可以帮窗口三完成后续工作。当然,多个用户之间可以通过 screen 实现简单的聊天需求。
screen 原理
我没有看过 screen 的源码啦,不过可以猜想一下其实现原理。
screen -S name
命令创建了 screen unix socket 服务端,同时也生成了当前终端的 screen 客户端;- 连接服务端后,客户端执行的任务通通由 screen 服务端的子进程执行,因此,终端窗口关闭之后不会影响到该任务;
- 同时,服务端将该 socket 接收到的输入输出同时定向到与该连接关联的类似于队列的结构中;
- 当有新的客户端 attach 到该 socket 时,将该 socket 相关的任务信息从队列中取出,写入到客户端连接中,以实现多客户端间实现信息共享;
- 当 socket 中的任务执行完毕,且超过指定时间仍然没有连接状态的客户端,则会关闭该 socket 连接;