linux system signal
一、信号的概念
- 信号随时发生,接受信号的进程也可以没有控制权
- 每个信号名都以SIG开头,包含在
中 - 当进程接收到一个信号,他可以对信号采取如下操作之一:
忽略这个信号
捕获这个信号,这需要执行一段称为信号处理器的特殊代码
允许执行信号的默认操作- 当进程对发送给它的信号采取措施,叫信号被传送
- 产生信号和递送信号之间的时间间隔叫做信号为决
- 进程不能简单的通过判断一个变量,如errno来判断是否出现一个信号
- 当进程接收到一个信号,他可以对信号采取如下操作之一:
二、捕获信号
- 当一个进程调用fork的时候,其子进程继承父进程的信号处理方式
所以信号捕捉函数的地址在子进程中式有意义的 - 利用函数指针回调函数捕获信号
- 进程捕捉到信号并对信号进行处理时,进程正在执行的指令序列临
时中断,它首先执行该信号处理程序中的指令 - 如果信号处理程序返回(没有调用exit(0)或者abort),则继续执行在
捕捉到信号时正在执行的正常指令序列 - 在信号处理程序中,不能判断捕捉到信号时进程正在何处执行
signal 函数(若为命令行,则使用kill向指定进程发送信号) /signal函数的例子/ } int main() } 三、发送信号 #include 2)raise函数 3)alarm函数 四、改进捕获信号机制 //参数signo是要检测或者修改其具体动作的信号编号 struct sigaction{ } /sigaction例子/ } int signal1(int signo,void (*func)(int)) } int main() } 五、使用自定义信号 void catch_Signal(int Sign) } int signal1(int signo,void (*func)(int)) } } /发送signal信号/ } 六、守护进程(daemon) 总结: setsid函数:pid_t setsid() chdir函数:int chdir(const char*pathname) umask函数:mode_t umask(mode_t mask) /创建守护进程代码/ } 守护进程写入系统日志: /syslog日志例子/ 使用信号与守护进程通信 } /通过脚本结束守护程序/ WHOAMI= PID= if(test "$PID"!="") then fi /通过脚本开启守护程序/ WHOAMI= PID= if(test "$PID"="") then fi 使用FIFO与守护进程通信 } /写FIFO/ } 如何让后台运行的daemon程序向屏幕打印信息 /daemon基础架构/ } void setdaemon() } void listenfifo() } void catch_Signal(int Sign) } }
#include
void (*signal(int signo,void (*func)(int)))(int);
//参数signo是前面表格中的信号名
//参数func式接收到此信号后要调用的函数。该函数有个int
型参数,int代表捕获到的信号值
void catch_Signal(int Sign)
{switch (Sign)
{
case SIGINT:
printf ("SIGINT Signal\n");
break;//改变了消息的用途,可以收到CTRL+C后退出进程
case SIGALRM:
printf ("HELLO\n");
exit(0);
}
{signal(SIGINT,catch_Signal);
signal(SIGALRM,catch_Signal);
pause ();
return 0;
1)kill
#include
int kill(pid_t pid,int sig)
//参数pid指定一个要杀死的信号,而sig是要发送的信号
#include
int raise(int signo);
//kill 函数将信号发送给进程,raise函数允许发信号给自身
//raise(signo)等价于kill(getpid(),signo);
#include
unsigned int alarm(unsigned int seconds);
//seconds是计时器时间到后时钟的秒数
//如果没有设置其他超时,函数返回0,否则返回值为前面安排超时中保留的秒数
//一个进程只能设置一次超时
//把second设置为0可以取消前面的超时设置
sigaction函数的功能是检查或修改与指定信号相关联的
处理动作,该函数替代了signal函数
#include
int sigaction (int signo,const struct sigaction *act, struct sigaction *oact);
(或同时执行这两种操作)
//如果act指针为空,则要修改其动作
//如果oact指针为空,则系统由oact指针返回该信号的上一个动作
//成功返回0,失败返回-1void (*sa_handle)(int);
void (*sasigaction)(int,siginfo_t *,void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer )(void);
void catch_Signal(int Sign)
{switch (Sign)
{
case SIGINT:
printf ("SIGINT Signal\n");
exit(0);
}
{struct sigaction act,oact;
act.sa_handler = func;//回调函数初始化
sigemptyset(&act.sa_mask);//初始化状态字集合,可以设置未决信号
act.sa_flags = 0;
return sigaction(signo,&act,&oact);
{signal1(SIGINT,catch_Signal);
pause();
return 0;
/自定义signal函数的例子/
int static status = 0;
{switch (Sign)
{
case SIGINT:
printf ("SIGINT Signal\n");
break;
case SIGUSR1:
status = 1;
}
{struct sigaction act,oact;
act.sa_handler = func;//回调函数初始化
sigemptyset(&act.sa_mask);//初始化
act.sa_flags = 0;
return sigaction(signo,&act,&oact);
/捕获SIGUSR1信号/
int main()
{signal1(SIGINT,catch_Signal);
signal1(SIGUSR1,catch_Signal);
printf("pid = %d\n",getpid());
while(1)
{
if(status = 1);
printf("SIGUSR1 UP!\n");
sleep(1);
}
return 0;
int main(int argc,char *args[])
{if(argc > 1)
{
kill(atoi(args[1],SIGUSR1);
printf("sent to %d\n",atoi(args[1]))
}
return 0;
文件系统上,那么就会妨碍这个文件系统被卸载)
一步是必要的)
1)父进程中执行fork,执行exit退出
2)在子进程中调用setid
3)让根目录'/'成为子进程的工作目录
4)把子进程的umask变为0
5)关闭不需要的文件描述符
//setsid函数创建一个新会话和一个新进程组,然后守护进程成为新会话的领导
//以及新进程组的领导
//setsid还保证新会话没有控制终端
//如果调用进程已经是一个进程组的领导进程,setsid会失败
//setsid调用成功返回新会话id,失败返回-1,并设置errno
//chdir函数根据参数pathname设置当前工作目录
//chdir函数调用成功返回0,失败返回-1,并设置errno
//umask调用把守护今晨的umask设置为0,这样取消了父进程的umask,避免了潜在的
//干扰创建文件和目录
int main()
{pid_t pid = fork();
if (pid == -1)
{
return -1;
}
if (pid > 0)
{
exit(0);
}
if(pid == 0)
{
setsid();//脱离控制台
chdir("/");//非必须,防止mount出错
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
while(1)
{
printf("hello\n");
sleep(1);
}
return EXIT_SUCCESS;
1)openlog函数打开日志:void openlog(const char *ident,int option,int facility);
//参数ident是要向每个消息加入的字符串,典型的情况是程序名称
//参数option是下面一个或多个值的"或"
名称 含义
LOG_CONS 如果系统日志服务器不能用, 写入控制台
LOG_NDELAY 立即打开连接,正常情况下,直到发送第一条消息才打开连接
LOG_PERROR 打印输出到stderr
LOG_PID 每条消息中包含进程PID
//参数facitity指定程序发送消息的类型
名称 含义
LOG_AUTHPRIV 安全授权信息
LOG_CRON 时钟守护进程,cron和at
LOG_DAEMON 其他系统守护进程
LOG_KERN 内核消息
LOG_LPR 打印机子系统
LOG_MAIL 邮件子系统
LOG_USER 默认
2)syslog写入日志:void syslog (int priority,const char * format,...)
//参数priority指定消息重要性
名称 含义
LOG_EMERG 系统不能使用
LOG_ALERT 立即采取措施
LOG_CRIT 紧急事件
LOG_ERR 出错条件
LOG_WARNING 警告条件
LOG_NOTICE 正常但重大事件
LOG_INFO 信息消息
LOG_DEBUG 调试信息
3)closelog关闭日志:void closelog(void);
syslog(LOG_INFO,"my daemon is OK!");
/严格说,openlog和closelog是可选的,因为函数syslog在首次使用的时候自动打开/
void catch_Signal(int Sign)
{switch(Sign)
{
case SIGTERM:
exit(EXIT_SUCCESS);
}
#!/bin/shwhoami
ps -u $WHOAMI | grep mydaemon | awk '{print} $1'
kill $PID
#!/bin/shwhoami
ps -u $WHOAMI | grep abc | awk '{print} $1'
./mydaemon
/读FIFO/
void readfifo()
{int len = 0;
char buf[1024];
memset(buf,0,sizeof(buf));
int fd = open ("/home/test/1/fifo",O_RDONLY);
while((len = read (fd,buf,sizeof(buf))>0))
{
printf("%s",buf);
}
close(fd);
return ;
void readfifo()
{int len = 0;
char buf[1024];
memset(buf,0,sizeof(buf));
int fd = open ("/home/test/1/fifo",O_WRONLY);
scanf("%s",buf);
write(fd,buf,sizeof(buf));
close(fd);
return ;
1 执行mkfifo创建一个管道文件
2 编译daemon,执行程序,关闭当前控制台终端窗口,让程序后台运行
3 打开一个新的终端窗口,通过ps aux找到进程pid
4 执行 #kill -s 2 PID;tty > fifo1
int signal1(int signo,void (*func)(int))
{struct sigaction act,oact;
act.sa_handler = func;//回调函数初始化
sigemptyset(&act.sa_mask);//初始化
act.sa_flags = 0;
return sigaction(signo,&act,&oact);
{pid_t pid,sid;
pid = fork();
if(pid < 0)
{
printf("fork failed %s\n",strerror(errno));
exit(EXIT_SUCCESS);
}
if(pid > 0)
{
exit(EXIT_SUCCESS);
}
if( (sid = setsid() ) < 0)
{
printf("setsid failed %s\n",strerror(errno));
exit(EXIT_SUCCESS);
}
{const char * sfifoname = "fifo1";
int len = 0;
char buf[128];
memset(buf,0,sizeof(buf));
int fd = open(sfifoname,O_RDONLY);
if(fd == -1)
{
printf("open %s failed,%s\n",sfifoname,strerror(errno));
}
len = read (fd,buf,sizeof(buf));
if(len > 0)
{
if (buf[strlen(buf) - 1] == '\n')
{
buf[strlen(buf) - 1] = 0;
}
close(STDOUT_FILENO);
open(buf,O_WRONLY);
}
close(fd);
{switch(Sign)
{
case SIGINT:
listenfifo();
break;
case SIGPIPE:
;
break;
}
int main(void)
{setdaemon();
signal1(SIGINT,catch_Signal);
signal1(SIGPIPE,catch_Signal);//不捕获会退出
while(1)
{
puts("!!!Hello World!!!");
sleep(1);
}
return EXIT_SUCCESS;