[Linux C编程]有名管道实现守护进程

本文介绍如何使用有名管道实现守护进程。守护进程是不受终端和用户登录影响的后台进程,而有名管道允许不同进程间通信。文章详细描述了创建守护进程的步骤,并提供了一个具体的实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有名管道实现守护进程

fork()函数创建子进程时,当父进程在运行时,终端都会被阻塞(即不能对当前终端进行任何操作,除非结束父进程);然而,只要父进程结束,不管子进程是否结束,终端都会解除阻塞(即在子进程运行的同时,当前终端也可以进行其他操作)。

 

守护进程:是始于系统开始运行,结束于系统结束,不受终端和用户登录、登出的影响,它是在后台运行的进程。在Linux下使用ps -s命令查看时,守护进程的TTY的一项是“?”。

 

创建守护进程的步骤为:

(1)在后台运行。使用fork()函数创建子进程,使其父进程结束,子进程运行。

(2)脱离控制终端,登录会话和进程组。使用setsid()函数(man setsid查看更详细的细节),将子进程建立新的会话组,并担任会话组长。

(3)禁止进程重新打开控制终端。由于会话组长拥有打开控制终端的权限,所以再次使用fork()函数,结束第一子进程(现在的父进程),继续第二子进程(不是会话组长)。
(4)关闭打开的文件描述符。进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们:for(i=0;i<sysconf(_SC_OPEN_MAX);i++) {close(i);} 。那么,什么是文件描述符呢?文件描述符是非负整数,打开显存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。习惯上,0表示标准输入,1表示标准输出,2表示标准错误。
(5)改变当前工作目录。进程活动时,其工作目录所在的文件系统是不能卸下的。一般需要将守护进程的工作目录改到根目录。使用chdir("/"),将工作目录改到了根目录。
(6)重设文件创建掩码。进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0); (参数0表示具有所有权限)

(7)处理SIGCHLD信号(软中断)。子进程结束时,会向其父进程发送SIGCHLD信号,父进程可以通过使用signal(SIGCHLD,SIG_IGN);函数来忽略这个信号,将它抛给init进程,init会回收子进程的资源,从而不会产生僵尸进程。

 有名管道:

(1)使两个不相关的进程彼此通信 a:通过路径名指出,在文件系统中可见

                                b:管道建立后,两进程可按普通文件一样对其操作

(2)遵循先进先出规则  a:对管道读从开始处返回数据

                       b:对管道写则把数据添加到末尾

 

 

下面我贴出我的用有名管道实现守护进程的代码,有误欢迎指正:

守护进程部分: 

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

#define FIFO "/tmp/myfifo"
 
void init_daemon()       //将程序转换成守护进程的函数
{
    int pid;
    int i;
 
    pid = fork();
 
    if(pid > 0)
    {
        exit(0);         //在后台运行,结束父进程
    }
    else if(pid < 0)
    {
        exit(1);
    }
 
    setsid();           //脱离控制终端,但是使子进程成为了会话组长,它拥有重新打开终端的权限
 
    pid = fork();
 
    if(pid > 0)
    {
        exit(0);        //禁止进程重新打开控制终端,结束第一子进程(现在的父进程)
    }
    else if(pid < 0)
    {
        exit(1);
    }
 
    for(i = 0; i < sysconf(_SC_OPEN_MAX); i++)  //关闭打开的文件描述符,循环关闭了所有的文件标识符
    {
        close(i);
    }
 
    chdir("/");              //改变当前目录,使进程在根目录下运行
    
    umask(0);       //重设文件创建掩码,参数0表示所有权限
 
    signal(SIGCHLD,SIG_IGN);    //处理SIGGHLD信号,在本程序中可以不用处理,因为父进程已经关闭掉了
 
    return;
 
}
int main(int argc,char ** argv)
{
    char r_buf[100];
 
    int count = 0;
    int fd;
    int nread;
 
    init_daemon();
    
     /* 创建管道 */
    if((mkfifo(FIFO,O_CREAT|O_EXCL) < 0) && errno != EEXIST)
    {
        printf("cannot creat fifoserver\n");
    }
 
    printf("Preparing for reading bytes...\n");
 
    memset(r_buf,0,sizeof(r_buf));
 
    /* 打开管道 */
    fd = open(FIFO,O_RDONLY|O_NONBLOCK,0);
 
    if(fd == -1)
    {
        perror("open");
 
        exit(1);
    }
 
    while(1)
    {
        memset(r_buf,0,sizeof(r_buf));
 
        if((nread = read(fd,r_buf,100)) == -1)
        {
            if(errno == EAGAIN)
            {
                printf("no data yet\n");
        
            }
        }
 
        if(nread == 0)
        {
            count++;
        }
        else if(nread > 0)
        {
            count = 0;
        }
 
        if(count > 6)
        {
            system("./write 123");  //重启被守护进程
        }
 
        printf("read %s from FIFO\n",r_buf);
 
        sleep(1);
    }
 
    pause();    /*暂停,等待信号*/
 
    unlink(FIFO);      /*s删除文件*/
 
    return 0;
}


被守护的进程:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
 
#define FIFO_SERVER "/tmp/myfifo"
 
int main(int argc,char ** argv)
{
    int fd;
    int count = 0;
    int nwrite;
 
    char w_buf[100];
   
     /*打开管道*/
    fd = open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
 
    if(argc == 1)
    {
        printf("please send something!\n");
 
        exit(-1);
    }
 
    while(count < 10)
    {
        memset(w_buf,0,sizeof(w_buf));
        strcpy(w_buf,argv[1]);
 
        /* 向管道写入数据 */
        if((nwrite = write(fd,w_buf,100)) == -1)
        {
            if(errno == EAGAIN)
            {
                printf("The FIFO has not been read yet,Please try later!\n");
            }
        }
        else
        {
            printf("write %s to the FIFO\n",w_buf);
        }
 
        sleep(1);
 
        count++;
    }
     
    if(10 == count)     //人为使进程挂起
    {
        exit(1);
    }
 
    pause();  /*暂停,等待信号*/
 
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值