1. 程式人生 > >今天部署Jar 遇到的問題,關閉ssh視窗是會自動結束了當前執行jar的程序

今天部署Jar 遇到的問題,關閉ssh視窗是會自動結束了當前執行jar的程序

解決方法,在執行jar的專案的時候加一個匯出nohup.out,複製匯出日誌,讓部署在後臺進行,後臺預設進行。

1 問題發現 之前在伺服器上起一個python的服務, 放到後臺執行. 我關閉這個SSH之後,該服務不可用,再次登入到伺服器,已經沒有這個python程序.

為此我寫了一個測試程式來描述此問題

///////////////////// //  hello.c ///////////////////// #include <stdio.h> #include <stdlib.h>

#include <unistd.h>

int main(void) {     while(1)     {         printf("pid = %d, I am coming...\n", getpid( ));

        sleep(3);     }

    return EXIT_SUCCESS; } 我們在一個ssh中編譯後啟動該程序

gcc hello.c -o hello -std=gnu99 -Wall ./hello 1 2

然後再開一個ssh, 我們用pidof hello來檢視程序的pid資訊, 顯示出程序的pid為29738

接著我們關掉那個啟動了hello的ssh, 重新用pidof hello再次檢視程序資訊, 發現程序已經沒了

其他程序的影響

守護程序不受此影響, 因為守護程序比較特殊, 不屬於sshd這個程序組 而是單獨的程序組,所以就算關閉了ssh,和他也沒有任何關係, 如果不這樣的話, 你發現nfs服務沒開. 你用ssh登入, 開啟了守護程序, 如果ssh退出後守護程序也退出了, 那豈不是白忙活了

使用後臺執行命令&, 不能將程式擺脫ssh程序組控制呢, 因為其本質仍然屬於此程序會話組的程序

2 問題定位 通過上面問題的表象,可以發現是跟SSH關閉有關。為什麼ssh關閉,會導致正在執行的程式死掉。通過檢視相關的資料,發現真正的元凶是SIGHUP訊號導致的.

在linux中,有下面幾個概念:

概念    描述 程序組    一個或多個程序的集合,每一個程序組都有唯一一個程序組ID,即程序組 會話器    一個或多個程序組的集合,有唯一一個會話期首程序(session leader). 會話期ID為首程序的ID 控制程序    與控制終端連線的會話期首程序叫做控制程序 當前與終端互動的程序稱為前臺程序組. 其餘程序組稱為後臺程序組.

一般縮寫:

PID = 程序ID (由核心根據延遲重用演算法生成) PPID = 父程序ID(只能由核心修改) PGID = 程序組ID(子程序、父程序都能修改) SID = 會話ID(程序自身可以修改,但有限制,詳見下文) TPGID= 控制終端程序組ID(由控制終端修改,用於指示當前前臺程序組) 1 2 3 4 5 會話和程序組的關係:

每次使用者登入終端時會產生一個會話(session). 從使用者登入開始到使用者退出為止,這段時間內在該終端執行的程序都屬於這一個會話

每個程序除了有一程序ID之外,還屬於一個程序組(Process Group)。程序組是一個或多個程序的集合,每個程序組有一個唯一的程序組ID。多個程序屬於程序組的情況是多個程序用管道“|”號連線進行執行。如果在命令列執行單個程序時這個程序組只有這一個程序.

結束通話訊號(SIGHUP)預設的動作是終止程式.

當終端介面檢測到網路連線斷開,將結束通話訊號傳送給控制程序(會話期首程序)

如果會話期首程序終止,則該訊號傳送到該會話期前臺程序組.

一個程序退出導致一個孤兒程序組中產生時,如果任意一個孤兒程序組程序處於STOP狀態,傳送SIGHUP和SIGCONT訊號到該程序組中所有程序.

結論:因此當網路斷開或終端視窗關閉後,也就是SSH斷開以後,控制程序收到SIGHUP訊號退出,會導致該會話期內其他程序退出.

簡而言之:就是ssh 開啟以後,bash等都是他的子程式,一旦ssh關閉,系統將所有相關程序殺掉!! 導致一旦ssh關閉,執行中的任務就取消了.

3 解決的辦法 3.1 nohup命令 如果你正在執行一個程序,而且你覺得在退出帳戶時該程序還不會結束,那麼可以使用nohup命令. 該命令可以在你退出帳戶/關閉終端之後繼續執行相應的程序. nohup就是不掛起的意思.

我們現在開始啟動服務 python pyserver.py,並且希望在後臺執行.我們就可以使用nohup,命令如下:

nohup ./hello & 1 此時預設地程式執行的輸出資訊放到當前資料夾的nohup.out 檔案中去,加不加&並不會影響這個命令。只是讓程式前臺或者後臺執行而已

然後另外一個ssh中, 我們用pidof hello來檢視程序的pid資訊, 顯示出程序的pid為29738

接著我們關掉那個啟動了hello的ssh, 重新用pidof hello再次檢視程序資訊, 發現程序仍然存在

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 引數指定命令的退出狀態 3.2 screen命令 如果想在關閉ssh連線後剛才啟動的程式繼續執行怎麼辦, 可以使用nohup.

但是如果要求第二天來的時候. 一開ssh, 還能檢視到昨天執行的程式的狀態,

然後繼續工作,這時nohup是不行了, 需要使用screen來達到這個目的.

雖然nohup很容易使用,但還是比較“簡陋”的,對於簡單的命令能夠應付過來,對於複雜的需要人機互動的任務就麻煩了

其實我們可以使用一個更為強大的實用程式screen。流行的Linux發行版通常會自帶screen實用程式,如果沒有的話,可以從GNU screen的官方網站下載

執行screen , 按任意鍵進入子介面;

我用./hello命令開始執行,如果下班了,但是想關閉ssh以後./hello繼續執行,那麼按ctrl+a再按d

這樣暫停了子介面,會顯示[detached]的字樣,這時候 我回到了父介面;

用screen –ls檢視目前子介面的狀態screen -ls

There is a screen on:     10869.pts-14.kylin (Detached)  Socket in /var/run/screens/S-gatieme. 如果回到子介面 用screen –r 22292,一下子彈到了./hello的子介面;