1. 程式人生 > 其它 >Linux學習總結(十五)程序組,會話,守護程序

Linux學習總結(十五)程序組,會話,守護程序

技術標籤:Linux

程序組

  程序組,也稱之為作業,BSD於1980年前後向unix中增加的一個新特性,代表一個或多個程序的集合,每個程序都屬於一個程序組,在waitpid函式和kill函式的引數中都曾使用導,作業系統設計的程序組的概念,是為了簡化對多個程序的管理。
  當父程序建立子程序的時候,預設子程序與父程序屬於同一個程序組,程序組ID=第一個程序ID(組長程序),所以,組長程序ID等於其程序組ID
  可以使用kill -SIGKILL -程序組ID(負的)來將整個程序組內的程序全部殺死。
  組長程序可以建立一個程序組,建立該程序組中的程序,然後終止,只要程序組中有一個程序存在,程序組就存在,與組長程序是否終止無關。

  程序組生命週期:程序組建立到最後一個程序離開(終止或轉移到另一個程序組)
  一個程序可以為自己或子程序設定程序組ID
  使用如下命令檢視程序組ID相關資訊:

ps ajx

在這裡插入圖片描述

程序組相關函式

獲取當前程序的程序組ID
 pid_t getpgrp(void); 總是返回呼叫者的程序組ID

獲取指定程序的程序組ID
 pid_t getpgid(pid_t pid); 成功:0;失敗:-1,設定errno
如果pid = 0,那麼該函式作用和getpgrp一樣。

改變程序預設所屬程序組,通常可用來加入一個現有的程序組或建立一個新程序組。
int setpgid(pid_t pid,pid_t pgid);成功0,失敗-1

將參1對應的程序,加入參2對應的程序組中。
注意:
1.如果改變子程序為新的組,應fork後,exec前
2.許可權問題,非root程序只能改變自己建立的子程序,或者有許可權操作的程序。
練習:修改子程序的程序組ID

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    pid_t pid;

    if ((pid = fork()) < 0) {
        perror("fork");
        exit(
1); } else if (pid == 0) { printf("child PID == %d\n",getpid()); printf("child Group ID == %d\n",getpgid(0)); // 返回組id //printf("child Group ID == %d\n",getpgrp()); // 返回組id sleep(7); printf("----Group ID of child is changed to %d\n",getpgid(0)); exit(0); } else if (pid > 0) { sleep(1); setpgid(pid,pid); //讓子程序自立門戶,成為程序組組長,以它的pid為程序組id sleep(13); printf("\n"); printf("parent PID == %d\n", getpid()); printf("parent's parent process PID == %d\n", getppid()); printf("parent Group ID == %d\n", getpgid(0)); sleep(5); setpgid(getpid(),getppid()); // 改變父程序的組id為父程序的父程序 printf("\n----Group ID of parent is changed to %d\n",getpgid(0)); while(1); } return 0; }

會話

建立一個會話需要注意以下6點:
1.呼叫程序不能是程序組組長,該程序變成新會話首程序。
2.該程序成為一個新程序組的組長程序。
3.需有root許可權(ubuntu不需要)
4.新會話丟棄原有的控制中斷,該會話沒有控制終端。
5.該呼叫程序是組長程序,則出錯返回
6.建立新會話時,先呼叫fork,父程序終止,子程序呼叫setsid。

getsid函式

獲取程序所屬的會話ID
pid_t getsid(pid_t pid);成功返回呼叫程序的會話ID,失敗返回-1
pid為0標識檢視當前程序會話ID
ps ajx:

  • a:不僅列出當前使用者的程序,也列出所有其他使用者的程序
  • j:列出與作業控制相關的資訊
  • x:不僅列出有控制終端的程序,也列出沒有控制終端的程序

組長程序不能成為新會話首程序,新會話首程序必定會成為組長程序

setsid函式

建立一個會話,並以自己的ID設定程序組ID,同時也是新會話ID
pid_t setsid(void);成功返回呼叫程序的會話ID,失敗返回-1
呼叫了setsid函式的程序,既是新的會長也是新的組長
練習:fork一個子程序,並使其建立一個新會話

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    pid_t pid;

    if ((pid = fork())<0) {
        perror("fork");
        exit(1);

    } else if (pid == 0) {

        printf("child process PID is %d\n", getpid());
        printf("Group ID of child is %d\n", getpgid(0));
        printf("Session ID of child is %d\n", getsid(0));

        sleep(10);
        setsid();       //子程序非組長程序,故其成為新會話首程序,且成為組長程序。該程序組id即為會話程序

        printf("Changed:\n");

        printf("child process PID is %d\n", getpid());
        printf("Group ID of child is %d\n", getpgid(0));
        printf("Session ID of child is %d\n", getsid(0));

        sleep(20);

        exit(0);
    }

    return 0;
}

守護程序

  daemon(精靈)程序,是Linux中的後臺服務程序,通常獨立於控制中斷並且週期性的執行某種任務或等待處理某些發生的事件,一般採用以d結尾的名字。
  Linux後臺的一些系統服務程序,沒有控制中斷,不能直接和使用者互動,不接受使用者登入和登出的影響,一直在執行著,他們都是守護程序,如:預讀入緩輸出機制的實現;ftp伺服器;nfs伺服器等。
  建立守護程序,最關鍵的一步是呼叫setsid函式建立一個新的session併成為sission leader.

建立守護程序

1.建立子程序,父程序退出
所有哦工作在子程序中進行形式上脫離了控制終端
2.在子程序中建立新會話
sesid()函式建立新會話,使子程序完全脫離出來,脫離控制
3.改變當前目錄為根目錄
chdir()函式,防止佔用可解除安裝的檔案系統,也可以換成其他路徑
4.重設檔案許可權掩碼
umask()函式
防止繼承的檔案建立遮蔽字拒絕某些許可權,增加守護程序靈活性
5.關閉檔案描述符
繼承的開啟檔案不會用到,浪費系統資源,無法解除安裝
6.開始執行守護經常核心工作
7.守護程序退出處理程式模型

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

void daemonize(void)
{
    pid_t pid;
    /*
     * * 成為一個新會話的首程序,失去控制終端
     * */
    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    } else if (pid != 0) /* parent */
        exit(0);
    setsid();
    /*
     * * 改變當前工作目錄到/目錄下.
     * */
    if (chdir("/") < 0) {
        perror("chdir");
        exit(1);
    }
    /* 設定umask為0 */
    umask(0);
    /*
     * * 重定向0,1,2檔案描述符到 /dev/null,因為已經失去控制終端,再操作0,1,2沒有意義.
     * */
    close(0);
    open("/dev/null", O_RDWR);
    dup2(0, 1);
    dup2(0, 2);
}

int main(void)
{
    daemonize();
    while(1); /* 在此迴圈中可以實現守護程序的核心工作 */
}