如何写一个Linux守护进程

2025-11-06 02:29:05

1、创建日志文件,用于记录守护进程的工作日志信息。

命令:touch file_name               // 创建文件

命令:chmod 777 file_name      // 修改文件权限为最高

如何写一个Linux守护进程

2、编译源码,生成守护进程的可执行文件。

命令:g++ -o output_file source_file    // 编译source_file,生成output_file

备注:源码文件名为demo.cpp

如何写一个Linux守护进程

3、运行,执行守护进程工作任务。

命令:./demo                                     // demo是可执行文件名

如何写一个Linux守护进程

4、查看守护进程的日志文件。按预期输出,工作OK。

命令:vim file_name                        // 查看file_name文件。此处为wlm。

如何写一个Linux守护进程

5、查看守护进程信息

命令:ps axj | grep "demo"      // 查看守护进程信息

命令:kill demo_id                   // 杀掉守护进程

如何写一个Linux守护进程

6、守护进程源码实现

注:最后一步,将提供可复制的源码。

如何写一个Linux守护进程

如何写一个Linux守护进程

如何写一个Linux守护进程

如何写一个Linux守护进程

7、/***********************************************************************

 *

 * 开发守护进程

 *

 **********************************************************************/

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/param.h>

#include <sys/stat.h>

#include <time.h>

#include <syslog.h>

#include <sys/resource.h>            // use getrlimit

#include <signal.h>                  // use sigaction

#include <stdlib.h>                  // use exit,system

void create_daemon(void)

{

// 文件描述符

int i, fd0, fd1, fd2;

// 进程ID

pid_t pid;

// 资源限制

struct rlimit rl;

// 信号动作

struct sigaction sa;

// 

// 函数:umask

// 功能:设置文件模式的屏蔽属性。即,通过umask可禁掉某些属性。

//

// 目的:调用umask将文件模式创建屏蔽字设置为0,确保所有文件模式可用。

//

umask(0);

//

// 函数:getrlimit(RLIMIT_NOFILE, **);

// 功能:获取资源限制,RLIMIT_NOFILE表示每个进程能打开的最大文件数。

// 

// 目的:获取文件描述符的信息

//

if(getrlimit(RLIMIT_NOFILE, &rl) < 0){

printf("can not get file limit");

return;

}

//

// 函数:fork

// 功能:创建子进程。子进程继承父进程的进程组ID,但具有一个新的进程ID。

//       这确保了,子进程不是一个进程组的组长进程。

//

// 函数:setsid

// 功能:创建新会话,当前进程是,新会话首进程,也是新会话的唯一进程。该进程

//       会成为一个新进程组的组长进程,新进程组ID就是该调用进程的进程ID

// 注意:如果调用进程是一个进程组的组长,则此函数会返回出错。为了确保不会

//       发生这种情况,通常先调用fork,然后使其父进程终止,而子进程则继续。

//

    // 目的:使得目标调用进程,达到以下目的。

//       a) 成为新会话的首进程

//       b) 成为一个新进程组的组长进程

//       c) 没有控制终端

//

if((pid = fork()) < 0){

printf("can not fork");

return;

}else if(pid != 0){

exit(0);

}

setsid();

//

    // 函数:sigemtpyset(sigset_t *set)

// 功能:初始化由set指向的信号集,清楚其中所有信号。

//

// 函数:int sigaction(int signo, const struct sigaction * restrict act, struct sigaction *restrict oact);

// 功能:检查或者修改与指定信号相互关联的处理动作。其中,参数signo是要检测或修改其具体动作的信号编号。

//       若act指针非空,则要修改其动作。如果oact指针非空,则系统经由oact指针返回该信号的上一个动作。

// 注意:SIG_IGN是常量,用于代替指向函数的指针。该函数需要一个整型参数,而且无返回值。

    //       #define SIG_DFL (void (*)())0

    //       #define SIG_IGN (void (*)())1        

// 

// 目的:忽略连接断开信号SIGHUP

//

sa.sa_handler = SIG_IGN;

sigemptyset(&sa.sa_mask);

sa.sa_flags = 0;

if(sigaction(SIGHUP, &sa, NULL) < 0){

printf("can not ignore SIGHUP");

return;

}

// 目的:再次fork,并使父进程终止。第二个子进程作为守护进程继续运行。这样就保证了该守护进程不是会话首进程。

//       可以防止它取得控制终端。

if((pid = fork()) < 0){

printf("can not fork");

return;

}else if(pid != 0){

exit(0);

}

// 

// 函数:chdir

// 功能:更改当前动作目录。当前工作目录是进程的一个属性。此目录是搜索相对路径名的起点。

//

// 目的:使得进程不与任何文件系统联系。

if(chdir("/usr/wlm/dev") < 0){

printf("can not change directory");

return;

}

// 目的:关闭不再需要的文件描述符。这使守护进程不再持有从其父进程继承来的某些文件描述符。

if(rl.rlim_max == RLIM_INFINITY){

rl.rlim_max = 1024;

}

for(i = 0;i< rl.rlim_max; i++){

close(i);

}

//

// 函数:int open(const char * pathname, int oflag, ...);

// 功能:打开或者创建一个文件。O_RDWR表示“读,写打开”

//

    // 函数:int dup(int filedes);

// 功能:复制一个现存的文件描述符,返回的新文件描述符一定是当前可用文件描述符中的最小数值。

//       通常等于输入的文件描述符+1;

//

// 目的:守护进程打开/dev/null使其具有文件描述符0,1,2。这样,任何一个试图读标准输入,

//       写标准输出,或者标准出错的例程都不会产生任何效果。因为守护进程并不与终端设备

//       相关联,所以不能在终端设备上显示其输出,也无处从交互式用户那里接收输入。

fd0 = open("/dev/null", O_RDWR);

fd1 = dup(0);

fd2 = dup(0);

if(fd0 != 0 || fd1 != 1 || fd2 != 2){

printf("unexpected file descriptors %d %d %d", fd0, fd1, fd2);

exit(1);

}

// 重点:守护进程做任务

//

// 函数:int system(const char * cmdstring);

// 功能:执行一个命令字符串。

// 示例:system("date > file");

//

system("echo \"hello,world!\\n\" >>  wlm");

time_t now;

while(1){

sleep(30);

//

// 函数:FILE * fopen(const char * restrict pathname, const char * restrict type);

// 功能:打开一个标准I/O流

// 注意:type="r+ 或r+b 或rb+",表示为读写而打开。

//       type="a+", 表示open or create for reading and writing at end of file

//

FILE * fd = fopen("wlm", "a+");

//

// 函数:time_t time(time_t * calptr);

// 功能:返回当前时间和日期

// 注意:返回时间值。如果参数不为空,则时间值也存放在由calptr指向的单元内

//

time(&now);

// 

// 函数:int fprintf(FILE *restrict fp, const char *restrict format, ...);

// 功能:写至指定的流

//

fprintf(fd, "system time:\t%s\t\t pid:%d\n", ctime(&now), getpid());

fclose(fd);

}

}

int main()

{

printf("hello,welcome to create daemon.\r\n");

// 创建守护进程

create_daemon();

return 0;

}

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢