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
- #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>
信号集函数组 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);
- }