Linux守护进程编写

环境:VMware 15 + ubuntu 16 内核:4.19

护进程的特点

  • 后台服务程序,随系统启动而启动。

  • 很多系统服务通过守护进程完成。

    • 守护进程的名字往往以字母‘d’结尾
  • 生存周期长。系统装入时启动,系统关闭时终止。

  • 周期性的执行某种任务或等待处理某些特别的事件。

  • 在Linux中,每一个与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端。但守护进程能突破这种限制,它从被执行开始,直到整个系统关闭时才退出.

依附:当控制终端被关闭时,依附于这个终端的进程都会自动的关闭。

守护进程编程一般步骤

  • 第一步、创建子进程、父进程退出

    编写守护进程的第一步就是使其独立与父进程,可以将父进程退出,子进程变成孤儿进程,并由init进程收养。为避免终端挂起,将父进程退出,造成程序已经退出的假象,所有后面的工作都在子进程完成,这样控制终端也可以继续执行其他命令,从而在形式上脱离控制终端的控制。

    • pid = fork(); //创建子进程

    • if (pid > 0)

      exit(0); //父进程退出

  • 第二步、在子进程中创建新的会话

    经过第一步,子进程已经有后台运行,而在fork()的时候,子进程复制了大量父进程的PCB,包括会话、进程组、控制终端等信息。尽管父进程已经退出,但子进程的会话、进程组、控制终端的信息没有改变。为使子进程完全摆脱父进程的环境,需要调用 setsid 函数。

    • setsid( ) //让进程脱离控制终端。

      通过调用 setsid 函数可以创建一个新会话,调用进程担任新会话的首进程,其作用有:

      • 使当前进程脱离原会话的控制
      • 使当前进程脱离原进程组的控制
      • 使当前进程脱离原控制终端的控制
  • 第三步、改变当前目录为根目录

    • chdir(“/”); //避免原工作目录不能被卸载

      直接调用 chdir 函数将切换到根目录下。
      由于进程运行过程中,当前目录所在的文件系统(如:“/mnt/usb”)是不能卸载的,为避免对以后的使用造成麻烦,改变工作目录为根目录是必要的。如有特殊需要,也可以改变到特定目录,如“/tmp”。

  • 第四步、重设文件权限掩码

    • umask(0); // 文件权限掩码设置成为0

      fork 函数创建的子进程,继承了父进程的文件操作权限,为防止对以后使用文件带来问题,需要重设文件权限掩码。调用 umask 设置文件权限掩码,通常是重设为 0,清除掩码,这样可以大大增强守护进程的灵活性。

      权限掩码:设定了文件权限中要屏蔽掉的对应位。这个跟文件权限的八进制数字模式表示差不多,将现有存取权限减去权限掩码(或做异或运算),就可产生新建文件时的预设权限。

  • 第五步、关闭文件描述符

    • for(i = 0;i < MAXFILE;i++)

      close(i); //关闭继承自父进程的文件

      同文件权限掩码一样,子进程可能继承了父进程打开的文件,而这些文件可能永远不会被用到,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下,因此需要一一关闭它们。由于守护进程脱离了终端运行,因此标准输入、标准输出、标准错误输出这3个文件描述符也要关闭。通过调用函数 getdtablesize 返回进程文件描述符表中的项数(即打开的文件数目):

      for (i=0; i < getablesize(); i++)close(i);

测试守护进程是否正常运行

/*向文件/home/emmmm/Desktop/program.log中隔一秒钟写入时间
*/
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<time.h>
#include<string.h>
#include<stdlib.h>int main(void){pid_t child;time_t rawTime;struct tm *timeInfor;FILE *pf;child = fork();if(child){exit(0);}setsid();//让进程脱离控制终端chdir("/");//避免原工作目录不被卸载umask(0);//文件权限掩码设置为0for(int i = 0; i<getdtablesize();i++){//关闭继承自父进程的文件close(i);}for(int i = 0;i<60;i++){pf = fopen("/home/emmmm/Desktop/program.log", "a");if(pf==NULL){printf("can't open the file!");return 0;}time(&rawTime);timeInfor = localtime(&rawTime);fprintf(pf, "pid = %d,and the time is ", getpid());fprintf(pf, "%d%d%d%d%d%d%d%d%d%d%d\n", timeInfor->tm_year + 1900,                            (timeInfor->tm_mon + 1)/10,(timeInfor->tm_mon + 1)%10, (timeInfor->tm_mday)/10, (timeInfor->tm_mday) % 10, (timeInfor->tm_hour)/10, (timeInfor->tm_hour)%10, (timeInfor->tm_min)/10, (timeInfor->tm_min)%10, (timeInfor->tm_sec)/10, (timeInfor->tm_sec)%10);fclose(pf);sleep(1);}return 0;}

测试结果:

如何获得正在运行的进程

方法一:

  在目录/proc/下有许多以数字命名的文件夹,这个目录下储存着系统所有进程的task_struct结构,研究了一下发现,那些数字命名的文件夹是正在运行进程的pid,进入这些文件夹找到state文件,这里面记录了正在运行pid的名称、状态等等信息。可以搜索/proc/目录来查看。

/*程序的状态*/
static const char * const task_state_array[] = {"R (running)",       /* 0x00 */"S (sleeping)",     /* 0x01 */"D (disk sleep)",   /* 0x02 */"T (stopped)",      /* 0x04 */"t (tracing stop)", /* 0x08 */"X (dead)",     /* 0x10 */"Z (zombie)",       /* 0x20 */"P (parked)",       /* 0x40 *//* states beyond TASK_REPORT: */"I (idle)",     /* 0x80 */
}

1.搜索该目录下的子文件名称:获取文件夹中文件夹的名称

2.读取/proc/xxx/state文件中关于进程的信息:一定要注意名字的长度管够,不然可能出现乱码

/*已知PID在文件中查找进程的状态*/
char* getNamebyPID(char *pid){char *name = (char*)malloc(sizeof(char*)*PRONUM);char path[BUFNUM];char buf[BUFNUM];sprintf(path, "/proc/%s/status", pid);FILE *pf = fopen(path, "r");if(pf == NULL){return name;}else{if( fgets(buf, BUFNUM-1, pf)== NULL ){fclose(pf);return name;}fclose(pf);sscanf(buf, "%*s %s", name);}return name;
}

方法二:

建立和命令行之间的管道,将输入命令行的结果重定向给文件流,通过文件流可以读取结果

参考:popen介绍

​ popen 建立管道

#include<stdio.h>//测试popen()int main(void){FILE *fp;char buf[1024];fp = popen("ps -A -o pid,user", "r");if(fp==NULL){printf("The commad doesn't work!");return 0;}else {while(fgets(buf, 1023, fp)!=NULL){printf("%s", buf);}pclose(fp);}return 0;
}

测试结果:

如何获得运行程序的起止时间

我选用的方法是每隔1秒钟判断查看一次正在运行的程序,如果程序在文件中出现,更新其终止时间,如果进程在原来的文件中不存在,则将不存在的进程相关信息写到文件的结尾。

但是还有一种方法,用上面的popen()方法,查看PS -A -o lstart,etime(etime表示进程持续运行的时间)

将该程序加入开机自启

我的内核版本是4.19的,因此用这个方法可以成功,但是在5.0.1版本以上就不能使用

开机自启for4.19

开机自启for5.0.1

检验

将文件删除后关机重启,看到有文件生成。点开文件后,不停有提示该文件内容发生改变,这样基本上就成功了。

参考:

Linux——ps指令介绍

通过pid 获取运行程序的名称

已知进程名获得pid

Linux下守护进程的实现

linux下是时间转字符串和字符串转时间

sscanf()函数介绍(真的超好用!!!!)

多种文件操作和字符串操作:fseek(), strcmp(), strcat()

Linux守护进程编写相关推荐

  1. linux 守护进程编写

    linux编程-守护进程编写 守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待 处理某些发生的事件.守护进程是一种很有用的进程. Linux的大多数服 ...

  2. linux+守护进程+php,【转载】Linux 守护进程的编程方法

    [转载]Linux 守护进程的编程方法 原文见: http://www.linuxdevelop.org/tingxx/show.php?table=c&id=3 Linux 守护进程的编程方 ...

  3. Linux 守护进程创建原理及简易方法

    1:什么是Linux下的守护进程 Linux daemon是运行于后台常驻内存的一种特殊进程,周期性的执行或者等待trigger执行某个任务,与用户交互断开,独立于控制终端.一个守护进程的父进程是in ...

  4. Linux守护进程的编程实现

    Linux 守护进程的编程方法 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程.Linux的大多数s ...

  5. 笔记整理--Linux守护进程

    Linux多进程开发(三)进程创建之守护进程的学习 - _Liang_Happy_Life__Dream - 51CTO技术博客 - Google Chrome (2013/10/11 16:48:2 ...

  6. linux守护进程编程,Linux守护进程的编程实现

    Linux 守护进程的编程方法 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程.Linux的大多数s ...

  7. linux - 守护进程的方式

    linux 守护进程 守护进程 start-stop-daemo crond 守护进程 start-stop-daemo 功能 启动和停止系统守护程序 位置 /sbin/start-stop-daem ...

  8. Linux守护进程实现

    Linux守护进程 redis版: void daemonize(void) {int fd;if (fork() != 0) exit(0); /* parent exits */setsid(); ...

  9. Linux 命令详解(六)Linux 守护进程的启动方法

    Linux 守护进程的启动方法 http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html

最新文章

  1. Windows——蓝屏[失败的操作:HardwareProtect_x64.sys]解决方案
  2. 8后淡入淡出没有了_8·30广州岑村ufo事件,人为制作的造假视频
  3. Angular中父子组件传值@Input @Output @ViewChild最全面最简单的总结
  4. watir6.0 -selenium3新时代的watir-webdriver
  5. 生产者消费者模型 java
  6. openstack常用运维命令_运维人员常用的Linux命令汇总
  7. MyCat分布式数据库集群架构工作笔记0006---Mycat启动
  8. Gevent Tutorial
  9. Web项目中前端页面通过URL传中文或 # 特殊字符到后台出现乱码解决方案
  10. cartographer编译过程遇到未定义的dlclose@@GLIBC_2.2.5
  11. SLF4J: The requested version 1.5.8 by your slf4j
  12. Ubuntu 12.04下安装OpenCV 2.3.1,图像二值化
  13. 使用 python 在多个word文件中提取关键字
  14. 什么是A*(Astar)算法?(简单叙述)
  15. 通过京东白条了解资产证券化
  16. 为何概述(翻译)CS229这个系列
  17. GLSurfaceView
  18. OpenCV第五章练习p163_5~8
  19. AutoCAD中程序化加载.NET程序集的方法
  20. C# hashTable的遍历【2种方法】与排序【3种方法】

热门文章

  1. MFC 创建模态与非模态对话框
  2. ARM GIC(三) gicv2架构
  3. 【turtle库】Python绘制圣诞树
  4. Given a binary search tree with its preorder traversal sequence { 8, 2, 15, 10, 12, 21 }.…
  5. Java中的数字工具类-----持续总结中
  6. CSS面试题整理汇总
  7. 查准率/查全率/F1指标
  8. 云计算平台技术及应用
  9. HM编码器代码阅读(9)——片编码器的初始化
  10. 为什么企业选择局域网即时通讯软件?局域网即时通讯软件哪家好?