ssh连接服务器中断,如何让命令继续在服务器执行

ssh连接linux服务器中断后,如何让命令继续在服务器运行

这个问题也许是我们这些小白比较头疼的问题,尤其对于那些做机器学习需要花很久的时间才能训练出一个结果。然而就在这时,因为各种不可抗力我们使用ssh连接服务器时,ssh的窗口突然断开了连接,那么在服务器上跑的程序就也跟着断掉了,之前所有跑的数据也将丢失,这样将会浪费我们大量的时间。

今天刚好有人跟我提到了这个问题,然后就简单上网查找资料,简单的学习一下,做个笔记方便自己以后查阅。

参考链接:

http://blog.csdn.net/gukesdo/article/details/6901902

为什么ssh一旦断开我们的进程也将会被杀掉?

元凶:SIGHUP 信号

让我们来看看为什么关掉窗口/断开连接会使得正在运行的程序死掉。

在Linux/Unix中,有这样几个概念:

进程组(process group):一个或多个进程的集合,每一个进程组有唯一一个进程组ID,即进程组长进程的ID。

会话期(session):一个或多个进程组的集合,有唯一一个会话期首进程(session leader)。会话期ID为首进程的ID。

会话期可以有一个单独的控制终端(controlling terminal)。与控制终端连接的会话期首进程叫做控制进程(controlling process)。当前与终端交互的进程称为前台进程组。其余进程组称为后台进程组。

根据POSIX.1定义:

挂断信号(SIGHUP)默认的动作是终止程序。

当终端接口检测到网络连接断开,将挂断信号发送给控制进程(会话期首进程)。

如果会话期首进程终止,则该信号发送到该会话期前台进程组。

一个进程退出导致一个孤儿进程组中产生时,如果任意一个孤儿进程组进程处于STOP状态,发送SIGHUP和SIGCONT信号到该进程组中所有进程。

因此当网络断开或终端窗口关闭后,控制进程收到SIGHUP信号退出,会导致该会话期内其他进程退出。

这里我认为我们的进程被杀掉也就是因为ssh与服务器之间的通信断掉了,这个通信断掉之后linux程序就默认将该连接下的所有进程都杀掉

解决方案

针对上面的问题,上面的参考链接中也有讲解,在此进行一个简单的整理。

这里主要有三个方案,一个是使用nohup指令,一个是使用screen指令,最后一个是screen的升级版byobu。看完这三个指令之后其实我更倾向于使用byobu指令,因为byobu指令更加的强大,是screen的升级版本,并且界面也比较友好。

nohup命令

nohup命令参考

  nohup 命令

  用途:不挂断地运行命令。

语法:nohup Command [ Arg … ] [ & ]

  描述:nohup 命令运行由 Command 参数和任何相关的 Arg 参数指定的命令,忽略所有挂断(SIGHUP)信号。在注销后使用 nohup 命令运行后台中的程序。要运行后台中的 nohup 命令,添加 & ( 表示”and”的符号)到命令的尾部。

无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup.out 文件中。如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。如果标准错误是一个终端,那么把指定的命令写给标准错误的所有输出作为标准输出重定向到相同的文件描述符。

nohup的简单使用

在执行命令时在命令前面加上nohup,然后回车开始运行。

这时你会发现该有的输出其实并没有输出出来,这个时候不要方,这是因为nohup命令将你的所有输出都输出到了当前文件夹下的nohup.out文件中,自己可以使用vim指令进行一个查看。

nohup命令及其输出文件
  nohup命令:如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用nohup命令。该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。nohup就是不挂起的意思( n ohang up)。
  该命令的一般形式为:nohup command &
  使用nohup命令提交作业
  如果使用nohup命令提交作业,那么在缺省情况下该作业的所有输出都被重定向到一个名为nohup.out的文件中,除非另外指定了输出文件:
  nohup command > myout.file 2>&1 &

使用 jobs 查看任务。

使用 fg %n 关闭。

screen命令

简单来说,Screen是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。Screen中有会话的概念,用户可以在一个screen会话中创建多个screen窗口,在每一个screen窗口中就像操作一个真实的telnet/SSH连接窗口那样。在screen中创建一个新的窗口有这样几种方式:

1.直接在命令行键入screen命令

$ screen
Screen将创建一个执行shell的全屏窗口。你可以执行任意shell程序,就像在ssh窗口中那样。在该窗口中键入exit退出该窗口,如果这是该screen会话的唯一窗口,该screen会话退出,否则screen自动切换到前一个窗口。

2.Screen命令后跟你要执行的程序。

$ screen 【后面跟你执行程序的命令】

Screen创建一个执行vi test.c的单窗口会话,退出vi将退出该窗口/会话。

3.以上两种方式都创建新的screen会话。我们还可以在一个已有screen会话中创建新的窗口。在当前screen窗口中键入C-a c ,即Ctrl键+a键,之后再按下c键,screen 在该会话内生成一个新的窗口并切换到该窗口。

screen还有更高级的功能。你可以不中断screen窗口中程序的运行而暂时断开(detach)screen会话,并在随后时间重新连接(attach)该会话,重新控制各窗口中运行的程序。

screen的简单使用

在所要执行的指令前添加screen.然后程序的运行等一切正常。(nohup的输出是定向到了nohup.out文件中,然而screen指令的输出是直接输出到了屏幕上的)

这个时候如果ssh终端断开了连接。我们只需要再次连接服务器然后输入指令

1
screen -ls

然后会得到类似下面的结果:

1
2
3
There is a screen on:
27267.pts-19.TITAN-X (09/08/2017 03:49:10 PM) (Detached)
1 Socket in /var/run/screen/S-huanghailiang.

这里就会显示ssh断开之前的程序,其实断开后程序依然在后台在运行,只是我们这个时候需要将它放到前台来运行。这个时候我们们已经通过screen -ls查询到了线程号是27267了,所以我们只需要执行下面的指令即可恢复到前台了。

1
screen -r 27267

如果想杀掉终端可以执行

1
kill 27267

其他更多的指令可以通过screen —help来进行学习。

当然screen还有更多的快捷键值得我们学习。我们可以通过C-a ? 即先按ctrl+a以后再按?即可查看。

通过观察我们可以发现它其实恢复了我们ssh断开前的那个界面。(所有的输出也都会在此显示出来)

byobu命令

byobu感觉就是screen的一个升级版本,界面比较友好,操作也比较方便。
一般Ubuntu系统开始的时候默认没有安装,我们需要手动安装byobu:

1
sudo apt install byobu

byobu的基本简单操作

按键 说明
F2 新建窗口
F3 移动到前一个窗口
F4 移动到后一个窗口
F6 退出byobu窗口
F9 打开byobu菜单,查看帮助信息的配置信息

关闭当前窗口其实Ctrl+D就可以完成

剩余操作我们可以F9查看byobu的帮助即可。

如果我们想要一登陆就显示byobu界面的话,可以使用指令

1
byobu-enable

如果想取消一登陆就显示byobu界面可以是用指令

1
byobu-disable

注(个人理解):

nohup虽然可以把所有的输出都写入到nohup.out中间来,但是在面对需要人机交互的时候它就不能正常使用了。另外在我做测试的时候,一旦ssh断开,虽然程序还在后台运行,但是好像并不会再把输出写入到nohup.out文件中,这一点很不好。

screen相比之下就强大了很多,不仅可以满足人机交互,而且还可以将所有的输出都再次展示出来,方便我们查看。我对screen的理解是,其实它是一个虚拟的终端,我们运行的时候screen指令就为我们创建了一个虚拟的终端,所以我们再次连接后我们打开的还是这个虚拟的终端,所以我们可以更好的进行操作,而且screen支持开很多个终端。

byobu相比之下继承了screen的所有优点,并且拥有了更加方便快捷的操作界面,同时在界面下方还能很好的显示目前计算机的硬件使用情况,十分方便。

它们三者的共性我认为都已经不受SIGHUP信号的影响了,所以即使断掉了ssh程序依旧会运行。