天天看點

Linux session(會話)

筆者在前文《Linux job control》中介紹了程序組(job)的概念以及常見的 job control 操作,本文接着介紹 session 的概念。本文中示範部分使用的環境為 ubuntu 18.04。

我們常見的 Linux session 一般是指 shell session。Shell session 是終端中目前的狀态,在終端中隻能有一個 session。當我們打開一個新的終端時,總會建立一個新的 shell session。

就程序間的關系來說,session 由一個或多個程序組組成。一般情況下,來自單個登入的所有程序都屬于同一個 session。我們可以通過下圖來了解程序、程序組和 session 之間的關系:

Linux session(會話)

會話是由會話中的第一個程序建立的,一般情況下是打開終端時建立的 shell 程序。該程序也叫 session 的領頭程序。Session 中領頭程序的 PID 也就是 session 的 SID。我們可以通過下面的指令檢視 SID:

Linux session(會話)

Session 中的每個程序組被稱為一個 job,有一個 job 會成為 session 的前台 job(foreground),其它的 job 則是背景 job(background)。每個 session 連接配接一個控制終端(control terminal),控制終端中的輸入被發送給前台 job,從前台 job 産生的輸出也被發送到控制終端上。同時由控制終端産生的信号,比如 ctrl + z 等都會傳遞給前台 job。

一般情況下 session 和終端是一對一的關系,當我們打開多個終端視窗時,實際上就建立了多個 session。

Session 的意義在于多個工作(job)在一個終端中運作,其中的一個為前台 job,它直接接收該終端的輸入并把結果輸出到該終端。其它的 job 則在背景運作。

通常,新的 session 由系統登入程式建立,session 中的領頭程序是運作使用者登入 shell 的程序。新建立的每個程序都會屬于一個程序組,當建立一個程序時,它和父程序在同一個程序組、session 中。

将程序放入不同 session 的惟一方法是使用 setsid 函數使其成為新 session 的領頭程序。這還會将 session 領頭程序放入一個新的程序組中。

當 session 中的所有程序都結束時 session 也就消亡了。實際使用中比如網絡斷開了,session 肯定是要消亡的。另外就是正常的消亡,比如讓 session 的領頭程序退出。一般情況下 session 的領頭程序是 shell 程序,如果它處于前台,我們可以使用 exit 指令或者是 ctrl + d 讓它退出。或者我們可以直接通過 kill 指令殺死 session 的領頭程序。這裡面的原理是:當系統檢測到挂斷(hangup)條件時,核心中的驅動會将 SIGHUP 信号發送到整個 session。通常情況下,這會殺死 session 中的所有程序。

session 與終端的關系

如果 session 關聯的是僞終端,這個僞終端本身就是随着 session 的建立而建立的,session 結束,那麼這個僞終端也會被銷毀。

如果 session 關聯的是 tty1-6,tty 則不會被銷毀。因為該終端裝置是在系統初始化的時候建立的,并不是依賴該會話建立的,是以當 session 退出,tty 仍然存在。隻是 init 系統在 session 結束後,會重新開機 getty 來監聽這個 tty。

如果我們在 session 中執行了 nohup 等類似的指令,當 session 消亡時,相關的程序并不會随着 session 結束,原因是這些程序不再受 SIGHUP 信号的影響。比如我們執行下面的指令:

Linux session(會話)

此時 sleep 程序的 sid 和其它程序是相同的,還可以通過 pstree 指令看到程序間的父子關系:

Linux session(會話)

如果我們退出目前 session 的領頭程序(bash),sleep 程序并不會退出,這樣我們就可以放心的等待該程序運作結果了。

nohup 并不改變程序的 sid,同時也說明在這種情況中,雖然 session 的領頭程序退出了,但是 session 依然沒有被銷毀(至少 sid 還在被引用)。重建立立連接配接,通過下面的指令檢視 sleep 程序的資訊,發現程序的 sid 依然是 7837:

Linux session(會話)

但是此時的 sleep 已經被系統的 1 号程序 systemd 收養了:

Linux session(會話)

setsid 會建立一個新的 session,它的目的是讓程序在背景執行指令,實作方式就是讓指令程序運作在一個新的與終端脫離的 session 中。看下面的示例:

查找之下居然沒有發現 sleep 程序的蹤迹:

Linux session(會話)

通過 grep 查詢 sleep 程序的 PID:

Linux session(會話)

去檢視 sleep 程序所在的 sid,發現是一個新的 session ID,并且沒有關聯終端:

Linux session(會話)

當一個程序通過調用 setsid 成為一個新的 session 領頭程序時,它會與控制終端斷開連接配接。

此時通過 pstree 檢視程序間的關系,發現 sleep 程序直接被系統的 1 号程序 systemd 收養了:

Linux session(會話)

控制終端是程序的一個屬性。通過 fork 系統調用建立的子程序會從父程序那裡繼承控制終端。這樣,session 中的所有程序都從 session 領頭程序那裡繼承控制終端。Session 的領頭程序稱為終端的控制程序(controlling process)。簡單點說就是:一個 session 隻能與一個終端關聯,這個終端被稱為 session 的控制終端(controlling terminal)。同時隻能由 session 的領頭程序來建立或者改變終端與 session 的聯系。我們可以通過 ps 指令檢視程序的控制終端:

Linux session(會話)

支援 job control 的 shell 必須能夠控制在某一時刻由哪個 job 使用終端。否則,可能會有多個 job 試圖同時從終端讀取資料,這會導緻程序在接收使用者輸入時的混亂。為了防止這種情況發生,shell 必須按照預定的協定與終端驅動程式協作。

shell 一次隻允許一個 job(程序組)通路控制終端。來自控制終端的某些輸入會導緻信号被發送到與控制終端關聯的 job(程序組)中的所有程序。該 job 被稱為控制終端上的前台 job。由 shell 管理的其他 job 在不通路終端的情況下,被稱為背景 job。

Shell 的職責是通知 job 何時停止何時啟動,還要把 job 的資訊通知給使用者,并提供機制允許使用者繼續暫停的 job、在前台和背景之間切換 job。比如前台 job 可以無限制的自由使用控制終端,而背景 job 則不可以。當背景 job 中的程序試圖從其控制終端讀取資料時,通常會向程序組發送 SIGTTIN 信号。這通常會導緻該組中的所有程序停止(變成 stopped 狀态)。類似地,當背景 job 中的程序試圖寫入其控制終端時,預設行為是向程序組發送 SIGTTOU 信号,但是否允許寫入的控制會更加的複雜。

參考:

What is the definition of a “session” in linux?

Linux session和程序組概述

Job Control

Linux TTY/PTS概述

setsid source code

作者:sparkdev

出處:http://www.cnblogs.com/sparkdev/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

繼續閱讀