[Linux C编程]有名管道实现守护进程
2016-10-24 23:26
309 查看
有名管道实现守护进程
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:对管道写则把数据添加到末尾
下面我贴出我的用有名管道实现守护进程的代码,有误欢迎指正:
守护进程部分:
被守护的进程:
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; }
相关文章推荐
- Linux进程通信 有名管道实现守护进程
- 简单的实现在有名管道里,进程间的通信(非阻塞)。
- Linux进程间的通信——有名管道fifo与守护进程deamon
- 利用有名管道实现连个独立进程的对话程序
- 有名管道的应用实例,创建两个有名管道实现全双工通信,两个进程间的聊天
- 利用有名管道,实现两个独立进程间的通讯
- 【转】C++ 进程间的通讯(一):简单的有名管道实现
- Linux下的有名管道(05)---使用两个管道实现两个进程之间的通信(对讲机模式)
- Linux下的有名管道(06)---使用两个管道实现两个进程之间的通信(手机模式)
- 进程守护+有名管道+无名管道
- linux中利用有名管道实现进程之间的通信
- 利用有名管道实现进程间的通信
- C++ 进程间的通讯(一):简单的有名管道实现
- 实现守护进程的步骤
- UNIX环境高级编程学习之第十五章进程间通信 - 通过匿名管道实现父子进程同步
- 守护进程的设计与实现
- 一个守护进程的两种实现
- UNIX环境高级编程学习之第十五章进程间通信 - 通过有名管道(命名管道)实现进程间通信
- 守护进程的日志实现
- 关于linux端php实现守护进程