linux里面进程间通信的另外一种方式就是信号通信。信号通信属于软件中的。
linux有如下几个常用的信号:
SIGHUP:终端上发出的结束信号
SIGINT :来自键盘的终端信号(CTRL+C)
SIGQUIT:来自键盘的退出信号(CTRL +\)
SIGFPE:浮点异常信号
SIGKILL:该信号结束接收信号的进程
SIGALRM:进程的定时器到期,发送该信号
SIGTERM:kill发送出的信号
SIGCHLD:标识子进程停止或结束的信号
SIGSTOP:来自键盘(CTRL+Z)或调试程序的停止信号
接收方有三种动作来对待信号:
1.忽略:SIGKILL、SIGSTOP例外
2.捕捉:执行终端服务程序
3.执行系统默认动作:(1)abort(2)exit(3)ignore(4)stop(5)continue
kill() and raise() method raise() method can send signals to the proc who invoke the raise method.
int kill(pid_t pid, int signo);
int raise(int signo);
返回值:成功,0;出错,-1.
对于kill里面的pid:pid>0:至指定pid proc;pid==0:至同进程组的其他proc;pid<0:至pid绝对值的proc。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> int main() { pid_t pid; int ret; if((pid=fork())<0){ perror("fork"); exit(1); } if(pid == 0){ raise(SIGSTOP); //向自身发送停止信号 exit(0); } else{ printf("pid=%d\n",pid); if((waitpid(pid,NULL,WNOHANG))==0){ if((ret=kill(pid,SIGKILL))==0) printf("kill %d\n",pid); else{ perror("kill"); } } } }
alarm() and pause() method.
alarm() can set a timer, when the timer is time out, then a SIGALRM signal will be sent to it.
the default action is to terminate the proc.
#include <unistd.h>
unsigned int alarm (unsigned int seconds);
pause() makes the proc which invokes it suspended, until it captures a signal.
#include <unistd.h>
int pause(void);
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { int ret; ret=alarm(5); pause(); /*printf("I have been waken up.\n",ret);*/ }
信号处理 signal()
void (*signal (int signo, void (*func));
返回:成功则为以前的信号处理配置,若出错则为SIG_ERR
func的值有三种:
(1)常数SIG_IGN
(2)常数SIG_DFL
(3)要调用的函数地址
#include <signal.h> #include <stdio.h> #include <stdlib.h> void my_func(int sign_no) { if(sign_no==SIGINT) printf("I have get SIGINT\n"); else if(sign_no==SIGQUIT) printf("I have get SIGQUIT\n"); } int main() { printf("Waiting for signal SIGINT or SIGQUIT \n "); signal(SIGINT, my_func); //注册SIGINT的处理函数,CTRL+C可以触发 signal(SIGQUIT, my_func); //注册SIGQUIT的处理函数,CTRL+\可以触发 pause(); exit(0); }
信号集函数组 signal set数据类型
#include <signal.h>
int sigemptyset ( sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset( sigset_t *set , int signo);
int sigdelset ( sigset_t *set , int signo);
返回值:成功,0;出错,-1。
int sigismember ( const sigset_t *set , int signo );
检查信号是否在信号集中。
int sigaction ( int signo, const struct sigaction *act, struct sigaction *oact);
检查或修改与指定信号相关的处理动作。
其中结构体参数 sigaction :
struct sigaction{ void (*sa_handler)(int signo); sigset_t sa_mask; int sa_flags; void (*sa_restore); }
#include <sys/types.h> #include <unistd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> void my_func(int signum) { printf("If you want to quit,please try SIGQUIT\n"); } int main() { sigset_t set,pendset; struct sigaction action1,action2; if(sigemptyset(&set)<0) //empty the set perror("sigemptyset"); if(sigaddset(&set,SIGQUIT)<0) //add SIGQUIT signal perror("sigaddset"); if(sigaddset(&set,SIGINT)<0) //add SIGINT signal perror("sigaddset"); if(sigprocmask(SIG_BLOCK,&set,NULL)<0) //阻塞中断 perror("sigprocmask"); else { printf("blocked\n"); sleep(5); } if(sigprocmask(SIG_UNBLOCK,&set,NULL)<0) //取消阻塞 perror("sigprocmask"); else printf("unblock\n"); while(1){ //进入死循环,不断询问是否有SIGINT OR SIGQUIT信号。CTRL+C:SIGINT,CTRL+\:SIGQUIT if(sigismember(&set,SIGINT)){ sigemptyset(&action1.sa_mask); action1.sa_handler=my_func; sigaction(SIGINT,&action1,NULL); }else if(sigismember(&set,SIGQUIT)){ sigemptyset(&action2.sa_mask); action2.sa_handler = SIG_DFL; sigaction(SIGTERM,&action2,NULL); } } }
守护进程
特点:生存期长;后台运行;系统引导时就装入,系统关闭时才终止
ps -e 中看到的以d结尾的进程即守护进程(daemon),终端名称为?号。
所有daemon均以超级用户的优先级运行
除了update外,所有的daemon process都是进程组的首进程
所有daemon process 的parent process 都是init process.
(1)create sub proc, terminate parent proc
(2)invoke setsid
(3)change current dir to /
(4)reset 文件权限掩码
(5)close the unneeded file descriptor
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<fcntl.h> #include<sys/types.h> #include<unistd.h> #include<sys/wait.h> #include<syslog.h> #define MAXFILE 65535 int main() { pid_t pc,sid; int i,fd,len; char *buf="This is a Dameon\n"; len =strlen(buf); pc=fork(); //create sub process if(pc<0) { printf("error fork\n"); exit(1); } else if(pc>0) //terminate parent process exit(0); setsid(); //1.脱离会话组;2.脱离进程组;3.脱离控制终端,变为后台进程 chidir("/"); //改变目录 umask(0); //对所有权限开放 for(i=0;i<MAXFILE;i++) //关闭所有不需要的文件描述符 close(i); if((fd=open("/tmp/daemon.log",O_CREATE | O_WRONLY | O_APPEND, 0600))<0) { perror("open"); exit(1); } while(1) { write(fd, buf, len+1); //写文件 sleep(2); //每两秒写一次 } close(fd); }
daemon的出错管理
通过syslog服务,将错误信息写到/var/log/message
openlog();
syslog():向日志文件里写入message
closelog();
#include <syslog.h>
void openlog( char *ident, int option, int facility );
ident: 要向每个消息加入的字符串,通常为程序名称
option: LOG_CONS, LOG_NDELAY, LOG_PERROR, LOG_PID
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<fcntl.h> #include<sys/types.h> #include<unistd.h> #include<sys/wait.h> #include<syslog.h> #define MAXFILE 65535 int main() { pid_t pc,sid; int i,fd,len; char *buf="This is a Dameon\n"; len =strlen(buf); pc=fork(); if(pc<0) { printf("error fork\n"); exit(1); } else if(pc>0) exit(0); openlog("demo_update",LOG_PID, LOG_DAEMON); if((sid=setsid())<0) { syslog(LOG_ERR, "%s\n", "setsid"); exit(1); } if((sid=chdir("/"))<0) { syslog(LOG_ERR, "%s\n", "chdir"); exit(1); } umask(0); for(i=0;i<MAXFILE;i++) close(i); if((fd=open("/tmp/dameon.log",O_CREAT|O_WRONLY|O_APPEND, 0600))<0) { syslog(LOG_ERR, "open"); exit(1); } while(1) { write(fd, buf, len+1); sleep(10); } close(fd); closelog(); exit(0); }