在ssh、telnet斷開以後繼續執行程序html
你是否是常常須要 SSH 或者 telent 遠程登陸到 Linux 服務器?你是否是常常爲一些長時間運行的任務而頭疼,好比系統備份、ftp 傳輸等等。一般狀況下咱們都是爲每個這樣的任務開一個遠程終端窗口,由於他們執行的時間太長了。必須等待它執行完畢,在此期間可不能關掉窗口或者斷開鏈接,不然這個任務就會被殺掉,一切半途而廢了。java
元兇:SIGHUP 信號
讓咱們來看看爲何關掉窗口/斷開鏈接會使得正在運行的程序死掉。
在Linux/Unix中,有這樣幾個概念:
進程組(process group):一個或多個進程的集合,每個進程組有惟一一個進程組ID,即進程組長進程的ID。
會話期(session):一個或多個進程組的集合,有惟一一個會話期首進程(session leader)。會話期ID爲首進程的ID。
會話期能夠有一個單獨的控制終端(controlling terminal)。與控制終端鏈接的會話期首進程叫作控制進程(controlling process)。當前與終端交互的進程稱爲前臺進程組。其他進程組稱爲後臺進程組。
根據POSIX.1定義:
掛斷信號(SIGHUP)默認的動做是終止程序。
當終端接口檢測到網絡鏈接斷開,將掛斷信號發送給控制進程(會話期首進程)。
若是會話期首進程終止,則該信號發送到該會話期前臺進程組。
一個進程退出致使一個孤兒進程組中產生時,若是任意一個孤兒進程組進程處於STOP狀態,發送SIGHUP和SIGCONT信號到該進程組中全部進程。
所以當網絡斷開或終端窗口關閉後,控制進程收到SIGHUP信號退出,會致使該會話期內其餘進程退出。
咱們來看一個例子。打開兩個SSH終端窗口,在其中一個運行top命令。
[root@tivf09 root]# top
在另外一個終端窗口,找到top的進程ID爲5180,其父進程ID爲5128,即登陸shell。
[root@tivf09 root]# ps -ef|grep top root 5180 5128 0 01:03 pts/0 00:00:02 top root 5857 3672 0 01:12 pts/2 00:00:00 grep top
使用pstree命令能夠更清楚地看到這個關係:
[root@tivf09 root]# pstree -H 5180|grep top |-sshd-+-sshd---bash---top
使用ps-xj命令能夠看到,登陸shell(PID 5128)和top在同一個會話期,shell爲會話期首進程,所在進程組PGID爲5128,top所在進程組PGID爲5180,爲前臺進程組。
[root@tivf09 root]# ps -xj|grep 5128 5126 5128 5128 5128 pts/0 5180 S 0 0:00 -bash 5128 5180 5180 5128 pts/0 5180 S 0 0:50 top 3672 18095 18094 3672 pts/2 18094 S 0 0:00 grep 5128
關閉第一個SSH窗口,在另外一個窗口中能夠看到top也被殺掉了。
[root@tivf09 root]# ps -ef|grep 5128 root 18699 3672 0 04:35 pts/2 00:00:00 grep 5128
----------------------------------------------------------------------------
Unix/Linux下通常想讓某個程序在後臺運行,不少都是使用 & 在程序結尾來讓程序自動運行。好比咱們要運行mysql
在後臺 /usr/local/mysql/bin/mysqld_safe –user=mysql &
可是咱們不少程序並不象mysqld同樣能夠作成守護進程 ,可能咱們的程序只是普通程序而已,通常這種程序即便使用 & 結尾,若是終端關閉,那麼程序也會被關閉。爲了可以後臺運行,咱們能夠忽略SIGHUP信號,關掉窗口應該就不會影響程序的運行了。nohup命令能夠達到這個目的,若是程序的標準輸出/標準錯誤是終端,nohup默認將其重定向到nohup.out文件。值得注意的是nohup命令只是使得程序忽略SIGHUP信號,還須要使用標記& 把它放在後臺運行。咱們須要使用nohup這個命令,好比咱們有個start.sh須要在後臺運行,而且但願在後臺可以一直運行,那麼就使用nohup:語法格式爲 nohup <command> [argument...] &
如 nohup /root/start.sh 在shell中回車後提示:
[~]$ appending output to nohup.out
原程序的的標準輸出被自動改向到當前目錄下的nohup.out文件,起到了log的做用。
可是有時候在這一步會有問題,當把終端關閉後,進程會自動被關閉,察看nohup.out能夠看到在關閉終端瞬間服務自動關閉。
諮詢紅旗Linux工程師後,他也不得其解,在個人終端上執行後,他啓動的進程居然在關閉終端後依然運行。
在第二遍給我演示時,我才發現我和他操做終端時的一個細節不一樣:他是在當shell中提示了nohup成功後還須要按終端上鍵盤任意鍵退回到 shell輸入命令窗口,而後經過在shell中輸入exit來退出終端;而我是每次在nohup執行成功後直接點關閉程序按鈕關閉終端.。因此這時候會斷掉該命令所對應的session,致使nohup對應的進程被通知須要一塊兒shutdown。
這個細節有人和我同樣沒注意到,因此在這兒記錄一下了。
附:nohup命令參考
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 參數指定命令的退出狀態。
nohup命令及其輸出文件
nohup命令:若是你正在運行一個進程,並且你以爲在退出賬戶時該進程還不會結束,那麼可使用nohup命令。該命令能夠在你退出賬戶/關閉終端以後繼續運行相應的進程。nohup就是不掛起的意思( n ohang up)。
該命令的通常形式爲:nohup command &
使用nohup命令提交做業
若是使用nohup命令提交做業,那麼在缺省狀況下該做業的全部輸出都被重定向到一個名爲nohup.out的文件中,除非另外指定了輸出文件:
nohup command > myout.file 2>&1 &
在上面的例子中,輸出被重定向到myout.file文件中。
使用 jobs 查看任務。
使用 fg %n 關閉。
另外有兩個經常使用的ftp 工具ncftpget和ncftpput,能夠實現後臺的ftp上傳和下載,這樣就能夠利用這些命令在後臺上傳和下載文件了。
----------------------------------------------------------------------------mysql
雖然nohup很容易使用,但仍是比較」簡陋」的,對於簡單的命令可以應付過來,對於複雜的須要人機交互的任務就麻煩了。
其實咱們可使用一個更爲強大的實用程序screen。流行的Linux發行版(例如Red Hat Enterprise Linux 4)一般會自帶screen實用程序,若是沒有的話,能夠從GNU screen的官方網站下載。
[root@tivf06 ~]# rpm -qa|grep screen xscreensaver-4.18-5.rhel4.11 screen-4.0.2-5
開始使用Screen
簡單來講,Screen是一個能夠在多個進程之間多路複用一個物理終端的窗口管理器。Screen中有會話的概念,用戶能夠在一個screen會話中建立多個screen窗口,在每個screen窗口中就像操做一個真實的telnet/SSH鏈接窗口那樣。在screen中建立一個新的窗口有這樣幾種方式:
1.直接在命令行鍵入screen命令
[root@tivf06 ~]# screen
Screen將建立一個執行shell的全屏窗口。你能夠執行任意shell程序,就像在ssh窗口中那樣。在該窗口中鍵入exit退出該窗口,若是這是該screen會話的惟一窗口,該screen會話退出,不然screen自動切換到前一個窗口。
2.Screen命令後跟你要執行的程序。
[root@tivf06 ~]# screen vi test.c
Screen建立一個執行vi test.c的單窗口會話,退出vi將退出該窗口/會話。
3.以上兩種方式都建立新的screen會話。咱們還能夠在一個已有screen會話中建立新的窗口。在當前screen窗口中鍵入C-a c ,即Ctrl鍵+a鍵,以後再按下c鍵,screen 在該會話內生成一個新的窗口並切換到該窗口。
screen還有更高級的功能。你能夠不中斷screen窗口中程序的運行而暫時斷開(detach)screen會話,並在隨後時間從新鏈接(attach)該會話,從新控制各窗口中運行的程序。例如,咱們打開一個screen窗口編輯/tmp/abc文件:
[root@tivf06 ~]# screen vi /tmp/abc
以後咱們想暫時退出作點別的事情,好比出去散散步,那麼在screen窗口鍵入C-a d (直接斷開鏈接也能夠的),Screen會給出detached提示:
暫時中斷會話sql
半個小時以後回來了,找到該screen會話:
[root@tivf06 ~]# screen -ls There is a screen on: 16582.pts-1.tivf06 (Detached) 1 Socket in /tmp/screens/S-root.
從新鏈接會話:
[root@tivf06 ~]# screen -r 16582
看看出現什麼了,太棒了,一切都在。繼續幹吧。
你可能注意到給screen發送命令使用了特殊的鍵組合C-a。這是由於咱們在鍵盤上鍵入的信息是直接發送給當前screen窗口,必須用其餘方式向screen窗口管理器發出命令,默認狀況下,screen接收以C-a開始的命令。這種命令形式在screen中叫作鍵綁定(key binding),C-a叫作命令字符(command character)。
能夠經過C-a ? 來查看全部的鍵綁定,經常使用的鍵綁定有:
C-a ? 顯示全部鍵綁定信息
C-a w 顯示全部窗口列表
C-a C-a 切換到以前顯示的窗口
C-a c 建立一個新的運行shell的窗口並切換到該窗口
C-a n 切換到下一個窗口
C-a p 切換到前一個窗口(與C-a n相對)
C-a 0..9 切換到窗口0..9
C-a a 發送 C-a到當前窗口
C-a d 暫時斷開screen會話
C-a k 殺掉當前窗口
C-a [ 進入拷貝/回滾模式
Screen經常使用選項
使用鍵綁定C-a ?命令能夠看到, 默認的命令字符(Command key)爲C-a,轉義C-a(literal ^a)的字符爲a:
Screen 經常使用選項shell
由於screen把C-a看做是screen命令的開始,因此若是你想要screen窗口接收到C-a字符,就要輸入C-a a。Screen也容許你使用-e選項設置本身的命令字符和轉義字符,其格式爲:
-exy x爲命令字符,y爲轉義命令字符的字符
下面命令啓動的screen會話指定了命令字符爲C-t,轉義C-t的字符爲t,經過C-t ?命令能夠看到該變化。
自定義命令字符和轉義字符bash
[root@tivf18 root]# screen -e^tt
其餘經常使用的命令選項有:
-c file 使用配置文件file,而不使用默認的$HOME/.screenrc
-d|-D [pid.tty.host] 不開啓新的screen會話,而是斷開其餘正在運行的screen會話
-h num 指定歷史回滾緩衝區大小爲num行
-list|-ls 列出現有screen會話,格式爲pid.tty.host
-d -m 啓動一個開始就處於斷開模式的會話
-r sessionowner/ [pid.tty.host] 從新鏈接一個斷開的會話。多用戶模式下鏈接到其餘用戶screen會話須要指定sessionowner,須要setuid-root權限
-S sessionname 建立screen會話時爲會話指定一個名字
-v 顯示screen版本信息
-wipe [match] 同-list,但刪掉那些沒法鏈接的會話
下例顯示當前有兩個處於detached狀態的screen會話,你可使用screen -r <screen_pid>從新鏈接上:
[root@tivf18 root]# screen -ls There are screens on: 8736.pts-1.tivf18 (Detached) 8462.pts-0.tivf18 (Detached) 2 Sockets in /root/.screen. [root@tivf18 root]# screen -r 8736
若是因爲某種緣由其中一個會話死掉了(例如人爲殺掉該會話),這時screen -list會顯示該會話爲dead狀態。使用screen -wipe命令清除該會話:
[root@tivf18 root]# kill -9 8462 [root@tivf18 root]# screen -ls There are screens on: 8736.pts-1.tivf18 (Detached) 8462.pts-0.tivf18 (Dead ???) Remove dead screens with 'screen -wipe'. 2 Sockets in /root/.screen. [root@tivf18 root]# screen -wipe There are screens on: 8736.pts-1.tivf18 (Detached) 8462.pts-0.tivf18 (Removed) 1 socket wiped out. 1 Socket in /root/.screen. [root@tivf18 root]# screen -ls There is a screen on: 8736.pts-1.tivf18 (Detached) 1 Socket in /root/.screen. [root@tivf18 root]#
-d -m 選項是一對頗有意思的搭檔。他們啓動一個開始就處於斷開模式的會話。你能夠在隨後須要的時候鏈接上該會話。有時候這是一個頗有用的功能,好比咱們可使用它調試後臺程序。該選項一個更經常使用的搭配是:-dmS sessionname
啓動一個初始狀態斷開的screen會話:
[root@tivf06 tianq]# screen -dmS mygdb gdb execlp_test
鏈接該會話:
[root@tivf06 tianq]# screen -r mygdb
管理你的遠程會話
先來看看如何使用screen解決SIGHUP問題,好比如今咱們要ftp傳輸一個大文件。若是按老的辦法,SSH登陸到系統,直接ftp命令開始傳輸,以後。。若是網絡速度還能夠,恭喜你,不用等太長時間了;若是網絡很差,老老實實等着吧,只能傳輸完畢再斷開SSH鏈接了。讓咱們使用screen 來試試。
SSH登陸到系統,在命令行鍵入screen。
[root@tivf18 root]# screen
在screen shell窗口中輸入ftp命令,登陸,開始傳輸。不肯意等了?OK,在窗口中鍵入C-a d:
管理你的遠程會話服務器
而後。。退出SSH登陸?隨你怎樣,只要別殺掉screen會話。
是否是很方便?更進一步,其實咱們能夠利用screen這種功能來管理你的遠程會話,保存你全部的工做內容。你是否是每次登陸到系統都要開不少窗口,而後天天都要重複打開關閉這些窗口?讓screen來幫你"保存"吧,你只須要打開一個ssh窗口,建立須要的screen窗口,退出的時候C-a d"保存"你的工做,下次登陸後直接screen -r <screen_pid>就能夠了。
最好能給每一個窗口起一個名字,這樣好記些。使用C-a A給窗口起名字。使用C-a w能夠看到這些窗口名字,可能名字出現的位置不一樣。使用putty:
putty網絡
使用telnet:
telnetsession
更多Screen功能
Screen提供了豐富強大的定製功能。你能夠在Screen的默認兩級配置文件/etc/screenrc和$HOME/.screenrc中指定更多,例如設定screen選項,定製綁定鍵,設定screen會話自啓動窗口,啓用多用戶模式,定製用戶訪問權限控制等等。若是你願意的話,也能夠本身指定screen配置文件。
以多用戶功能爲例,screen默認是以單用戶模式運行的,你須要在配置文件中指定multiuser on 來打開多用戶模式,經過acl*(acladd,acldel,aclchg...)命令,你能夠靈活配置其餘用戶訪問你的screen會話。更多配置文件內容請參考screen的man頁。
-------------------------------------
實際應用中碰到的問題
[root@dev ~]# screen -ls
There is a screen on:
4083.down_video (Detached)
1 Socket in /var/run/screen/S-root.
狀態顯示 down_video這個screen session已經被 斷開(detach)
此時咱們用screen -r能夠取回進行,
說明: -r :取回一個已被斷開的screen session
例: [root@dev ~]# screen -r down_video
能夠看到咱們的程序仍在運行,中間不曾中止,並且此時咱們又能夠控制它了。app
那麼如何中斷一個 screen session?
看例子:
[root@dev ~]# screen -ls
There is a screen on:
4083.down_video (Attached)
1 Socket in /var/run/screen/S-root.
請注意: 當前看到的session : down_video 正在被鏈接使用中,
這時我想使用此session
[root@dev ~]# screen -r down_video
There is a screen on:
4083.down_video (Attached)
There is no screen to be resumed matching down_video.
此時用 -r 不能取到此 screen session
這時只能用 -d 參數來強制中斷它
[root@dev ~]# screen -d down_video
[4083.down_video detached.]
[root@dev ~]# screen -r down_video
再用 -r 取回 screen就成功了
注意:原來的被咱們中斷的鏈接會顯示 :
[root@dev ~]# screen -r down_video
[remote detached]
文章出處:飛諾網(www.diybl.com):http://www.diybl.com/course/3_program/java/javajs/20100719/455597.html