守护进程深度分析_学习笔记

  • 新会话关联控制终端的方法

    • 会话首进程成功打开终端设备 ( 设备打开前处于空闲状态 )
      1. 关闭标准输入输出和标准错误输出
      2. 将 stdin 关联到终端设备:STDIN_FILENO -> 0 输入
      3. 将 stdout 关联到终端设备:STDOUT_FILENO -> 1 输出
      4. 将stderr 关联到终端设备:STDERR_FILENO -> 2 错误
  • 一些相关推论

    • 新会话关联控制终端后,会话中的所有进程生命期与控制终端相关
    • 只有会话首进程能够关联控制终端 ( 会话中的其它进程不行 )
    • 进程的标准输入输出标准错误输出可以进行重定向
      • 由描述符 0,1,2 决定重定向的目标位置(按顺序打开设备)
      • 控制终端与进程的标准输入输出以及标准错误输出无直接关系

#master.c

#define _XOPEN_SOURCE  600
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int main()
{
    char rx = 0;
    int master = 0;
    int c = 0;
    
    master = posix_openpt(O_RDWR); // gnome-terminal
    
    if( master > 0 )
    {
        grantpt(master);
        unlockpt(master);
        
        printf("Slave: %s\n", ptsname(master));
        
        while( (c = read(master, &rx, 1)) == 1 )
        {
            if( rx != '\r' )
            {
                printf("%c", rx);
            }
        }
        
        close(master);
    }
    else
    {
        printf("create pty error...\n");
    }
    
    return 0;
}

#session.c 


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

int main(int argc, char* argv[])
{
    int pid = 0;
    int i = 0;
    
    if( (pid = fork()) > 0 )
    {
        printf("parrent = %d, ppid = %d, pgid = %d, sid = %d\n", getpid(), getppid(), getpgrp(), getsid(getpid()));
        printf("new: %d\n", pid);
        exit(0);
    }
    else if( pid == 0 )
    {
        setsid();
        
        sleep(200);
        
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
        
        i += open(argv[1], O_RDONLY);  // 0 --> STDIN
        i += open(argv[1], O_WRONLY);  // 1 --> STDOUT
        i += open(argv[1], O_RDWR);    // 2 --> STDERR
        
        printf("child = %d, ppid = %d, pgid = %d, sid = %d\n",
        getpid(), getppid(), getpgrp(), getsid(getpid()));
        printf("i = %d\n", i);
    }
    else
    {
        printf("fork error...\n");
    }  
    
    sleep(240);
    
    return 0;
}

  • 什么是守护进程(Daemon)?

    • 守护进程是系统中执行任务的后台进程

      • 不与任何终端相关联(不接收终端相关的信号)
      • 生命周期长,一旦启动,正常情况下不会终止(直到系统退出)
      • Linux大多数服务器使用守护进程实现(守护进程名以后缀d结尾)
  • 守护进程的创建步骤

  1. 通过 fork()创建新进程,成功后,.父进程退出
  2. 子进程通过 setsid() 创建新会话
  3. 子进程通过 fork() 创建孙进程(肯定不是会话首进程)
  4. 孙进程修改模式 umask(),改变工作目录为"/"
  5. 关闭标准输入输出和标准错误输出
  6. 重定向标准输入输出和标准错误输出("/dev/nu")
  • 守护进程关键点分析
    • 父进程创建子进程是为了创建新会话
    • 子进程创建孙进程是为了避免产生控制进程
    • 孙进程不是会话首进程,因此不能关联终端
    • 重定向操作可以避开奇怪的进程输出行为

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


int main(int argc, char* argv[])
{
    int pid = 0;
    int i = 0;
    
    if( (pid = fork()) > 0 ) // 1
    {
        printf("parrent = %d, ppid = %d, pgid = %d, sid = %d\n",
        getpid(), getppid(), getpgrp(), getsid(getpid()));
        printf("child: %d\n", pid);
        exit(0);
    }
    else if( pid == 0 )
    {
        setsid(); // 2
        
        if( (pid = fork()) > 0 )  // 3
        {
            printf("child = %d, ppid = %d, pgid = %d, sid = %d\n",
            getpid(), getppid(), getpgrp(), getsid(getpid()));
            printf("groundson: %d\n", pid);
            exit(0);
        }
        
        if( pid == 0 )
        {   
            // 4
            umask(0); 
            chdir("/"); 
            // 5
            close(STDIN_FILENO);
            close(STDOUT_FILENO);
            close(STDERR_FILENO);
            // 6
            i += open("/dev/null", O_RDONLY);  // 0 --> STDIN
            //放上绝对路径
            i += open("/home/ubuntu/TestCode/Linux/d.log", O_WRONLY);  // 1 --> STDOUT
            i += open("/dev/null", O_RDWR);    // 2 --> STDERR
            
            printf("child = %d, ppid = %d, pgid = %d, sid = %d\n", 
            getpid(), getppid(), getpgrp(), getsid(getpid()));
                       
            while( 1 )
            {
                // do something
                printf("i = %d\n", i++);
                sleep(1);
                fflush(stdout);			//强制将缓存区的内容写入到文件
            }
        }
    }
    else
    {
        printf("fork error...\n");
    }  
    
    return 0;
}

 运行结果:

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值