守护进程-解析

Posted hntea-hong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了守护进程-解析相关的知识,希望对你有一定的参考价值。

守护进程-解析

1.概念:守护进程也称为精灵进程,是生存期较长的一种进程

a) 系统自举启动,系统关闭时终止

b) 没有控制终端,在后台运行

2.终端查看守护进程

a) ps -axj

i. -a 显示由其他用户所拥有的进程状态

ii. -x 显示没哟控制终端的进程状态

iii. -j 显示与作业有关的信息

b) 显示解析

i. PPID:父进程

ii. PID:进程

iii. PGID:进程组

iv. SID:会话ID

v. TTY:终端名称

vi. TPGID:终端进程组ID

vii. UID:用户ID

viii. COMMAND:命令字符串

3.父进程ID0的各进程通常是内核进程,作为系统自举过程的一部分而启动

4.LINUX下的守护进程

a) keventd:为在内核中运行计划执行的函数提供进程上下文

b) kapmd:对计算机系统提供高级电源管理支持

c) kswapd:页面调出守护进程

d) bdflushkupdated:将高速缓存中的数据冲洗到磁盘上

e) Portmap:端口映射进程,提供远程过程调用

f) ...

5.编程规则

a) 调用umask(0) : 将文件模式创建屏蔽字设置为0

b) 调用fork():创建子进程,

i. 继承父进程的进程组ID,但具有一个新的进程ID

ii. 保证子进程不是一个进程组的组长进程(进程ID与进程组ID相等)

c) 调用exit(0):退出父进程

d) 调用setsid():创建一个新会话(session)是一个或多个进程组的集合

i. 该进程变成新会话首进程,此时该进程是新会话中的唯一进程

ii. 该进程将成为一个新的进程组的组长进程

iii. 该进程没有控制终端

e) 调用 chdir(“/”)将当前工作目录更改为 “根目录”

f) 关闭不再需要的文件描述符

i. 使守护进程不再持有父进程继承过来的某些文件描述符

 

 

 

守护进程惯例

 

1.若守护进程使用锁文件,该文件通常放在/var/run目录中

a) 锁文件命名格式:守护进程名/服务名.pid

2.若支持配置选项

a) 配置文件通常放在 /etc目录,命名格式 name.conf

3.守护进程可用命令行启动,但是通常它们是由系统初始化脚本

a) /etc/rc*

b) /etc/init.d/*

 

4.守护进程终止,应当自动的从新启动

a) /etc/inittab中为该守护进程包括 _respawn记录项,这样init就将重启该守护进程

 

守护进程出错记录

1.用户进程(守护进程)大多调用函数

a) syslog(3):产生日志消息

i. 使消息发送至UNIX域数据报套接字 /dev/log

b) syslogd 守护进程读取三种格式的日志消息

i. UNIX域数据报套接字

ii. 因特网域数据报套接字

iii. 内核例程

iv. 启动过程

1. 读取配置文件 /etc/syslog.conf :该文件决定不同种类的消息送往何处

v. 接口函数

1. openlog

2. syslog

3. closelog

4. setlogmask

vi. 问题来了,输出的消息在哪个文件呢?

2.syslog 日志输出文件程序设计

a) 寻找配置文件 /etc/rsyslog.conf 配置文件

b) 在配置文件最后添加自己用户程序的调试文件

i. 格式如下

ii. 消息来源.优先级 /日志文件所在路径

iii. 消息来源-syslog(第一个参数决定)

iv. 优先级同上

1. 例如 syslog(LOG_DAEMON|LOG_DEBUG,.........,...);

2. 配置文件修改:

a) daemon.debug /var/log/文件名

3. 配置文件生效

a) 在终端输入:service syslog restart

4. 执行应用程序后查看日志

v. 具体/usr/include/sys/syslog.h文件中有相关的标志说明

 

例子-设计云公交刷卡器守护进程

1.任务设计:

a) 系统自启动

b) 监测刷卡动作

c) 读取数据并以固定格式写入指定文件

d) 写入前清空文件数据

 

****************************************************

作者:hntea

函数功能:公交打卡机数据采集

日期:2016/3/1

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

#include <stdio.h>

#include <string.h>

#include <sys/types.h>

#include <errno.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdlib.h>

#include <time.h>

#include <sys/times.h>

#include <sys/resource.h>

 

#define CONFIG_DEBUG 0 /*打印函数开关*/

#ifdef CONFIG_DEBUG

#define BUSCARD_DBG(formate...) do \\

if(CONFIG_DEBUG) \\

printf(formate); \\

while(0)

#endif

 

#define OUT_FILE_NAME "/hntea/bus301.txt"

#define BAUD_RATE 9600

#define DEV_PATH "/dev/ttyUSB0"

 

extern int openTermio(const char* devPath);

extern int termiosetup(int fd,int nSpeed, int nBits, char nEvent, int nStop);

typedef struct ibuscard

unsigned char card_nm_first; /*第一个卡号,触发条件*/

unsigned char card_nm[3]; /*磁卡号码*/

unsigned int  balance; /*余额*/

unsigned int expens_money; /*票价*/

unsigned char expens_num; /*消费次数*/

const char* out_file_name; /*数据输出文件名*/

const char* out_path; /*数据输出路径*/

const char* ttyusb_port; /*设备挂载端口*/

unsigned int baud_rate; /*设备波特率*/

IBUS_CARD;

 

IBUS_CARD* card_data; /*全局结构--需要分配内存*/

struct tm* local_time; /*全局结构--需要分配内存*/

 

void delay(int x,int y)

int i,j;

for(i=x;i>0;i--)

for(j=y;j>0;j--);

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

/*

函数名称:daemoinit()

函数功能:守护进程初始化

参数说明:

*/

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

void daemoinit(void)

int i = 0;

pid_t pid = 0;

struct rlimit r1;

 

/*创建守护进程*/

/*1.屏蔽文件模式*/

umask(0);

/*2.创建子进程*/

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

BUSCARD_DBG("Create chile process err!\\n");

exit(1); /*无法创建直接退出*/

else if(pid != 0)

/*3.退出父进程*/

BUSCARD_DBG("Create chile process success!\\n");

exit(0);

 

/*4.退出终端,创建新会话*/

setsid();

/*5.切换工作目录*/

chdir("/");

/*6.1 获取文件最大描述符*/

if(getrlimit(RLIMIT_NOFILE,&r1) < 0)

BUSCARD_DBG("get RLIMIT_NOFILE err!\\n");

return ;

/*6.2 关闭所有文件描述符*/

for(i=0;i<r1.rlim_max;i++)

close(i);

 

 

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

函数名称:getTime

函数功能:时间显示格式化 年--日 时:分:秒:毫秒

参数说明:

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

static struct tm* getTime(void)

unsigned char* buf ;

time_t timeval;

struct tm *localtime;

int fd;

/*获取当前时间和日期*/

timeval = time(&timeval);

/*时间分割*/

localtime = gmtime(&timeval);

/*格式化打印*/

#if 0

printf("%d-%d-%d %d:%d:%d\\n",\\

localtime->tm_year+1900,\\

localtime->tm_mon, \\

localtime->tm_mday, \\

localtime->tm_hour, \\

localtime->tm_min, \\

localtime->tm_sec \\

);

#endif

return localtime;

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

/*

函数名称:readDataFromBusCard()

函数功能:读取磁卡数据

参数说明:

fd:文件语句柄

bus_card:将读到的数据存放到该数据结构中并作为返回值

*/

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

 

static struct IBUS_CARD* readDataFromBusCard(int fd,IBUS_CARD* card_data)

int ret = 0;

unsigned char first_char=0;

int read_times=1,i=0; /*只读取一次*/

unsigned char tem[6];

/*清空数组*/

bzero(tem,6);

while(1)

/*终端数据录入太慢,无法一次性全部读取,要一次性全读取需要一定延时*/

while(!(ret = (read(fd,&first_char,1)))); /*等待数据录入*/

usleep(7000);

while(!(ret = (read(fd,tem,7)))); /*等待数据录入*/

/*跳过空数据,无数据在此等待*/

if((tem[0]>0)&&read_times)

/*fill data*/

read_times=0;

card_data->card_nm_first = first_char;

memcpy(card_data->card_nm,tem,3); /*fill card_num,填充时还有要算上分割符号*/

card_data->balance = tem[3]; /*最大只能显示到256*/

card_data->expens_money = tem[4]; /*fill expens_money*/

card_data->expens_num = tem[5]; /*fill expend_num*/

 

#if 0

printf("carnum:%x-%x-%x-%x balance %d expensmoney %d exxpensnumber %d \\n",

card_data->card_nm_first,

card_data->card_nm[0],

card_data->card_nm[1],

card_data->card_nm[2],

card_data->balance,

card_data->expens_money,

card_data->expens_num

);

#endif

break;

return card_data;

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

函数名称:wtiteFormate

函数功能:时间显示格式化 年--日 时:分:秒:毫秒 aa bb cc dd ee ff gg

参数说明:

localtime:当地时间结构体

card_data:要格式写入的卡数据

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

void wtiteFormate(struct tm *localtime,IBUS_CARD* card_data)

/*标准I/O操作*/

/*创建标准I/O流 对象*/

FILE *fp;

/*以可读可写方式打开流,文件不存在时自动创建*/

fp = fopen(OUT_FILE_NAME, "w+");

fprintf(fp,"%d-%d-%d %d:%d:%d%x %x %x %x %x %x %x\\n",\\

localtime->tm_year+1900,\\

localtime->tm_mon, \\

localtime->tm_mday, \\

localtime->tm_hour, \\

localtime->tm_min, \\

localtime->tm_sec, \\

card_data->card_nm_first, \\

card_data->card_nm[0], \\

card_data->card_nm[1], \\

card_data->card_nm[2], \\

card_data->balance, \\

card_data->expens_money,\\

card_data->expens_num

);

/*关闭流*/

fclose(fp);

 

 

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

/*

函数名称:daemowork()

函数功能:守护进程任务

参数说明:

*/

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

void daemowork(int fd,IBUS_CARD* card_data,struct tm* local_time)

/*守护进程的工作*/

#if 0

card_data = readDataFromBusCard(fd,card_data); /*读取卡数据*/

local_time = getTime(); /*获取时间*/

wtiteFormate(local_time,card_data); /*格式化写入文件*/

#endif

 

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

/* 主函数

功能:打开串口,设置串口属性,在后台处理数据(守护进程)

参数:

argc:命令个数---> 执行文件本身算一个命令,放在 argv[0]

argv: 命令参数

int main(int argc,const char* argv[])

*/

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

int main(void)

int termio_fd = 0;

int ret=0;

 

/*为结构体分配内存*/

card_data = malloc(sizeof(IBUS_CARD));

local_time = malloc(sizeof(struct tm));

/*1.创建守护进程*/

daemoinit();

 

/*2初始化串口*/

/*2.1.打开终端设备文件设备文件*/

termio_fd = openTermio(DEV_PATH);

/*2.2.设置串口*/

ret = termioSetup(termio_fd,9600,8,'N',1);

while(1)

card_data = readDataFromBusCard(termio_fd,card_data); /*读取卡数据*/

local_time = getTime(); /*获取时间*/

wtiteFormate(local_time,card_data); /*格式化写入文件*/

free(card_data);

free(local_time);

return 0;

 

以上是关于守护进程-解析的主要内容,如果未能解决你的问题,请参考以下文章

installd守护进程

常见redis.conf解析

编写我的 linux 守护进程的首选方法是啥?

RegEX - 查找Track 1和Track 2子串的磁卡字符串

rsync 数据备份同步 守护进程(socket)方式

Android 进阶——Framework 核心之Binder对象管理者 Service Manager 守护进程及其自身代理对象详解