问题描述:
每次SSH到服务器上,然后运行了一个自己写的服务端程序,比如 ./myserver.sh ,然后关闭ssh或者终端之后,发现服务不能访问。
简要分析下:
根据 这篇博文 的提示,ssh登录后会新建一个会话,一个登陆shell发起的会话,一般由一个会话首进程、一个前台进程组、一个后台进程组组成。通常来说,会话首进程是一个登录shell,比如bash。进程组是一个或多个进程的集合,进程组属于一个会话。一般来说,一个进程组中的其它进程的父进程是进程组组长进程的ID,如果,这个进程组组长终止掉之后,这个进程组中其它进程会变成孤儿进程,这个进程组也就成了孤儿进程组。对于后台进程组来说,后台进程组中的进程可以向终端设备写,但是当一个后台进程组中的进程尝试读终端设备的时候,会收到一个SIGTTIN信号,然后停止。当一个进程组成为孤儿进程组的时候,Bash无法知晓其PID,那么就无法将其放入前台,当其试图读终端设备的时候,read()调用将失败,并将errno置为EIO。
总结下就是,ssh登录后,bash都是其子进程,一旦会话终止,该会话期的所有相关的进程都会被杀死。包括后台进程。&是没有用的。
解决方案:
那么怎么解决这个问题呢?使用nohup命令。nohup命令会忽略SIGTTIN信号,从而可以在会话结束之后还可以继续运行。
比如上面的例子中,就可以使用:
nohup ./myserver.sh &
后面的&可以加也可以不用加,区别就是是否是后台。和挂断没有关系。
具体的使用方法在 http://zjking.blog.51cto.com/976858/1117828 这篇博客中有提到。
如果要在下次会话的时候还想恢复到上次会话终止前的状态,比如说我用nmap扫描某个IP段,下次登录进来要看到扫描结果。
我们可以使用screen命令。
1.使用screen进入到子界面中,然后nmap -A xxxxxxx 2.按 ctrl + a ,d 暂停子界面。这时会显示[detached],并且回到父界面。 3.想干啥干啥去。 4.查看子界面状态 screen -ls There is a screen on: 447.pts-1.free (Detached) 这里的447就是子界面的进程号。 5.回到子界面 screen -r 子界面pid 比如:screen -r 447 6.在子界面杀死子界面的办法是先ctrl + a ,然后按k。 具体的使用办法可以 screen -h