问题描述:
之前在服务器上起一个python的服务,放到后台运行。 python pyserver.py &. 当我关闭这个SSH之后,该服务不可用,再次登入到服务器,已经没有这个python进程啦。
问题定位:
通过上面问题的表象,可以发现是跟SSH关闭有关。为什么ssh关闭,会导致正在运行的程序死掉。通过查看相关的资料,发现真正的元凶是SIGHUP信号导致的。
在linux中,有下面几个概念:
进程组: 一个或多个进程的集合,每一个进程组都有唯一一个进程组ID,即进程组
会话器: 一个或多个进程组的集合,有唯一一个会话期首进程(session leader)。会话期ID为首进程的ID。
控制进程: 与控制终端连接的会话期首进程叫做控制进程.
当前与终端交互的进程称为前台进程组。其余进程组称为后台进程组。
一般缩写:
- PID = 进程ID (由内核根据延迟重用算法生成)
- PPID = 父进程ID(只能由内核修改)
- PGID = 进程组ID(子进程、父进程都能修改)
- SID = 会话ID(进程自身可以修改,但有限制,详见下文)
- TPGID= 控制终端进程组ID(由控制终端修改,用于指示当前前台进程组)
会话和进程组的关系:
每次用户登录终端时会产生一个会话(session)。从用户登录开始到用户退出为止,这段时间内在该终端执行的进程都属于这一个会话。
每个进程除了有一进程ID之外,还属于一个进程组(Process Group)。进程组是一个或多个进程的集合,每个进程组有一个唯一的进程组ID。多个进程属于进程组的情况是多个进程用管道“|”号连接进行执行。如果在命令行执行单个进程时这个进程组只有这一个进程。
挂断信号(SIGHUP)默认的动作是终止程序。
当终端接口检测到网络连接断开,将挂断信号发送给控制进程(会话期首进程)。如果会话期首进程终止,则该信号发送到该会话期前台进程组。一个进程退出导致一个孤儿进程组中产生时,如果任意一个孤儿进程组进程处于STOP状态,发送SIGHUP和SIGCONT信号到该进程组中所有进程。
因此当网络断开或终端窗口关闭后,也就是SSH断开以后,控制进程收到SIGHUP信号退出,会导致该会话期内其他进程退出。
解决的办法
nohup命令:
如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用nohup命令。该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。nohup就是不挂起的意思。
我们现在开始启动服务 python pyserver.py,并且希望在后台运行.我们就可以使用nohup,命令如下:
nohup python pyserver.py &
此时默认地程序运行的输出信息放到当前文件夹的nohup.out 文件中去,加不加&并不会影响这个命令。只是让程序前台或者后台运行而已。
nohup命令说明:
用途:不挂断地运行命令。
语法:nohup Command [ Arg ... ] [ & ]
描述:nohup 命令运行由 Command 参数和任何相关的 Arg 参数指定的命令,忽略所有挂断(SIGHUP)信号。在注销后使用 nohup 命令运行后台中的程序。要运行后台中的 nohup 命令,添加 & ( 表示“and”的符号)到命令的尾部。
无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup.out 文件中。如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。如果标准错误是一个终端,那么把指定的命令写给标准错误的所有输出作为标准输出重定向到相同的文件描述符。
退出状态:该命令返回下列出口值:
- 126 可以查找但不能调用 Command 参数指定的命令。
- 127 nohup 命令发生错误或不能查找由 Command 参数指定的命令。
否则,nohup 命令的退出状态是 Command 参数指定命令的退出状态。
使用 jobs 查看任务,使用 fg %n关闭。
延伸:
为什么守护程序就算ssh 打开的,就算关闭ssh也不会影响其运行?
因为他们的程序特殊,比如httpd –k start运行这个以后,他不属于sshd这个进程组 而是单独的进程组,所以就算关闭了ssh,和他也没有任何关系!
[[email protected] ~]# pstree |grep http
|-httpd
[[email protected] ~]# pstree |grep top
|-sshd-+-sshd—bash—top
守护进程的启动命令本身就是特殊的,和一般命令不同的,比如mysqld_safe 这样的命令 一旦使用了 就是守护进程运行。所以想把一般程序改造为守护程序是不可能。