linux高编之信号守护进程
2013-10-14 22:23
183 查看
linux系统启动时会有很多系统服务进程,它们没有控制终端,不能直接和用户交互,在用户登录或运行程序时创建,在程序运行结束或用户注销时终止,这样的进程叫做守护进程。在linux终端下可用命令ps axj查看:
其中TPGID为-1的列就是系统中的守护进程。守护进程是很有用的,比如Internet服务器,Web服务器进程等等,都是运行在后台。守护进程运行在后台,类似于Windows中的系统服务。
2、创建守护进程
创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。
#include <unistd.h>
pid_t setsid(void);
该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。注意,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进程组的Leader也很容易,只要先fork再调用setsid就行了。fork创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,在子进程中调用setsid就不会有问题了。
下面就写一个最简单的守护进程:
运行程序之后查看,a.out已经变为了守护进程了:
之前写过一个服务器端与客户端通信的函数,现在学了守护进程了,我们可以将服务器端改为守护进程,这样服务器端就可以一直在后台运行了,其实很简单,就是在服务器端的函数中用fork创建一个进程,然后在子进程中调用我们刚才写的创建守护进程的函数就可以了,程序如下:
这里有个注意的小地方,调用守护进程函数之后不能再次用文件描述符了,因为我在守护进程函数中已经把文件描述符重定向到/dev/null中了,若要再次使用,要重新定向。
其中TPGID为-1的列就是系统中的守护进程。守护进程是很有用的,比如Internet服务器,Web服务器进程等等,都是运行在后台。守护进程运行在后台,类似于Windows中的系统服务。
2、创建守护进程
创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。
#include <unistd.h>
pid_t setsid(void);
该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。注意,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进程组的Leader也很容易,只要先fork再调用setsid就行了。fork创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,在子进程中调用setsid就不会有问题了。
下面就写一个最简单的守护进程:
#include <stdlib.h> #include <stdio.h> #include <fcntl.h> void daemonize(void) { pid_t pid; if((pid=fork())<0){ perror("fork"); exit(1); }else if(pid!=0) //如果是父进程就退出 exit(0); setsid(); //在子进程中创建守护进程 if(chdir("/")<0){ //改变守护进程工作路径 perror("chdir"); exit(1); } close(0); //关闭文件描述符 open("/dev/null",O_RDWR); dup2(0,1); //将文件描述符1、2都重定向到0,然后再将其定向到/dev/null dup2(0,2); } int main(void) { daemonize(); //调用创建守护进程函数 while(1); return 0; }
运行程序之后查看,a.out已经变为了守护进程了:
之前写过一个服务器端与客户端通信的函数,现在学了守护进程了,我们可以将服务器端改为守护进程,这样服务器端就可以一直在后台运行了,其实很简单,就是在服务器端的函数中用fork创建一个进程,然后在子进程中调用我们刚才写的创建守护进程的函数就可以了,程序如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <fcntl.h> #include <signal.h> #define MAXLINE 80 void daemonize(void) { pid_t pid; if((pid=fork())<0){ perror("fork"); exit(1); }else if(pid!=0) exit(0); setsid(); if(chdir("/")<0){ perror("chdir"); exit(1); } close(0); open("/dev/null",O_RDWR); dup2(0,1); dup2(0,2); signal(SIGCHLD,SIG_IGN); } int main(void) { struct sockaddr_in servaddr,cliaddr; socklen_t cliaddr_len; int listenfd,connfd; int p,length=0; char *ip; char *port=NULL; FILE *fp_config; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; int i,n; pid_t pid; fp_config=fopen("config.txt","r"); if(fp_config<0){ printf("open file error!\n"); return 1; } getline(&port,&length,fp_config); for(i=0;i<strlen(port);i++){ if(port[i]=='\n') port[i]='\0'; } p=atoi(port); daemonize(); //看这里,调用创建守护进程函数 listenfd=socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(p); bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); listen(listenfd,20); while(1){ cliaddr_len=sizeof(cliaddr); connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); n=read(connfd,buf,MAXLINE); for(i=0;i<n;i++) buf[i]=toupper(buf[i]); write(connfd,buf,n); close(connfd); } }
这里有个注意的小地方,调用守护进程函数之后不能再次用文件描述符了,因为我在守护进程函数中已经把文件描述符重定向到/dev/null中了,若要再次使用,要重新定向。
相关文章推荐
- linux多进程——进程组与会话、守护进程、信号通信 .
- Linux信号处理和守护进程
- 二十三、Linux 进程与信号---进程链和进程扇、守护进程和孤儿进程以及僵尸进程
- linux多进程——进程组与会话、守护进程、信号通信
- linux多进程——进程组与会话、守护进程、信号通信
- Linux守护进程加上发送信号固定模式
- linux 守护进程 daemon
- linux 进程通信之 信号
- linux下的僵尸进程处理SIGCHLD信号
- linux下创建守护进程(daemon process)代码-详细注释
- linux下的守护进程
- Linux下开发-守护进程(daemon)
- linux下的僵尸进程处理SIGCHLD信号
- Linux中 终端、作业控制与守护进程
- Linux守护进程介绍
- linux 进程通信-信号学习总结(1)
- Linux简单的守护进程
- linux之守护进程与操作编程
- Linux下的守护进程(daemon)(代码保留)
- linux守护进程daemon