网络编程(13)—— 利用信号处理函数signal和sigaction销毁僵尸进程
2016-10-09 23:10
639 查看
一、引言
上一文中介绍了利用wait函数和waitpid函数来销毁僵尸进程,本文主要介绍利用Linux中的信号处理机制来销毁僵尸进程。linux中的信号处理类似于windows中的消息处理,基本的编程步骤就是先在系统中注册信号和对应的信号处理函数,我们用代码或者 系统自动产生注册的信号时会调用该信号处理函数。我们下面要介绍的signal函数和sigaction函数实际上就是我们用来向操作系统注册信号和信号处理函数的api。二、signal函数
signal函数的原型如下:#include <signal.h> typedef void (*sighandler_t)(int); void signal(int signum, sighandler_t handler);
signum,要处理的信号,一般用宏来表示,如:
SIGALRM,通过alarm函数触发的闹钟信号;
SIGINT,输入Ctrl+C时系统自动产生的信号;
SIGCHIL,子进程终止 时产生的信号;
handler,信号处理器,就是我们自己定义的信号处理函数的函数指指针。
这里简单介绍下alarm函数:
#include <unistd.h> unsigned int alarm(unsigned int seconds);
该函数接收一个int类型的参数,表示过了参数传递的秒之后,就会产生一个SIGALRM信号,当传给其0时,表示之前预约的SIGALRM将取消。特别指出的是如果调用该函数时,未指定对应的SIGALRM信号处理器,该函数将会迫使进程强制退出,此时就类似于exit()的作用了。
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<signal.h> void timeout(int sig) { if(sig==SIGALRM) puts("Time out"); alarm(2); } void keycontrol(int sig) { if(sig==SIGINT) puts("CTRL + C pressed"); } int main() { int i; signal(SIGALRM,timeout); signal(SIGINT,keycontrol); alarm(2); for(i=0;i<3;i++) { puts("wait..."); sleep(100); } return 0; }
上述代码实现的功能是分别用signal注册SIGALRM和SIGINT的信号处理函数timeout和keycontrol。用alarm函数注册一个闹钟,2秒之后发送一个SIGALRM信号,然后到达2秒后,timeout被调用,打印出字符串“Time out”。如此反复3次。如果用户按下了Ctrl+C,会产生一个SIGINT信号,该信号的处理函数keycontrol会打印一个字符串“CTRL + C pressed”。我们先来看下结果:
[Hyman@Hyman-PC csdn]$ ./a.out wait... Time out wait... ^CCTRL + C pressed wait... Time out
另外需要注意的是:
1、按下Ctrl + C时,信号会被signal捕获,而不会再终止进程。
2、调用信号处理器时将会唤醒正在sleep中的程序,也就是说上述程序不会再sleep 100秒
二、sigaction函数
sigaction函数完全可以替代signal函数,而且使用sigaction函数还有一个好处就是:signal函数会随着Unix版本的不同而不同,但是每个版本的sigaction的都是一样的。sigacton的原型如下:#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
signum,和signal的参数一样,传递的都是信号信息。
act,sigaction结构体,里面包含信号处理函数等信息。
oldact,通过此参数获取之前注册的sigaction结构体指针,如果不需要,直接设置0
先看一下sigaction结构体:
struct sigaction { void (*sa_handler)(int); sigset_t sa_mask; int sa_flags; }sa_handler就是我们需要处理信号的信号处理函数指针,其他两个参数用来指定信号相关的选项和特性,一般情况下指定为0即可,指定的方法将下面的代码。
#include<stdio.h> #include<unistd.h> #include<signal.h> void timeout(int sig) { if(sig==SIGALRM) puts("Time out"); alarm(2); } int main() { int i=0; struct sigaction act; act.sa_handler=timeout; sigemptyset(&act.sa_mask); act.sa_flags=0; sigaction(SIGALRM,&act,0); alarm(2); for(i=0;i<3;i++) { puts("wait ..."); sleep(100); } return 0; }
上述代码实现了和上面signal的代码同样的功能,只不过没有处理SIGINT信号,结果我们不再展示。下面主要介绍下利用sigaction处理子进程的结束:
#include<stdio.h> #include<unistd.h> #include<signal.h> #include<sys/wait.h> void childproHandler(int sig) { int status; pid_t pid; if(sig==SIGCHLD) { pid = waitpid(-1,&status,WNOHANG); if(WIFEXITED(status)) { printf("removed prc id:%d \n",pid); printf("child send:%d \n",WEXITSTATUS(status)); } } } int main() { pid_t pid; struct sigaction act; act.sa_handler=childproHandler; sigemptyset(&act.sa_mask); act.sa_flags=0; sigaction(SIGCHLD,&act,0); pid=fork(); if(pid==0) { puts("I'm child process"); sleep(10); return 12; } else { printf("child process id %id\n",pid); pid=fork(); if(pid==0) { puts("I'm child process"); sleep(10); exit(24); } else { int i=0; printf("child process id:%d\n",pid); for(i=0;i<5;i++) { puts("wait ..."); sleep(5); } } } return 0; }
第6行我们定义了一个SIGCHIL的信号处理函数,在这个函数中我们用waitpid来回收子进程资源。请注意signal和sigaction只是信号处理函数的注册api,其本身没有销毁僵尸进程的作用,我们还需要借助wait或者waitpid来销毁僵尸进程。
第24到28行,分别定义sigaction结构体变量以及利用sigaction注册信号已经对应的信号处理函数。
第29和39行,分别fork一个子进程,等到这两个子进程结束,操作系统就会产生一个SIGCHIL信号,就会调用我们定义的信号处理函数,输出我们定义的打印信息。
结果如下:
[Hyman@Hyman-PC csdn]$ ./a.out child process id 2472d child process id:2473 wait ... I'm child process I'm child process wait ... wait ... removed prc id:2472 child send:12 wait ... wait ... [Hyman@Hyman-PC csdn]$
Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本项目:
git clone git@github.com:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL13
相关文章推荐
- Linux下利用signal函数处理ctrl+c等信号
- Linux下利用signal函数处理ctrl+c等信号
- 标准库函数---信号处理函数--signal
- Linux内核-信号之signal处理函数
- 标准库函数---信号处理函数--signal
- signal signal函数每次设置具体的信号处理函数(非SIG_IGN)只能生效一次,多次调用需要调用时在加类似监听的方法!!! 最好用sigaction
- Linux信号来源和捕获处理以及signal函数简介
- linux之信号处理函数signal和sigaction
- 设置信号信号处理函数void (*signal (int signo ,void (*fun)(int )))(int)
- [学习笔记]信号基本概念(中断和信号)/名称及常用信号/信号处理/signal函数实践
- 信号处理函数signal的使用
- python练习笔记——利用信号signal处理僵尸进程
- 信号处理之signal 函数笔记
- 关于 Linux 中 signal 函数信号处理的讨论
- 信号处理signal、sigaction、pause、信号嵌套处理、不可重入函数
- Linux环境编程之信号处理(三、利用alarm()和pause()函数实现sleep()函数)
- C/C++ signal 信号处理函数
- Xcode里调试signal的信号回调处理函数
- 《UNIX环境高级编程》笔记--信号及其处理函数signal
- Linux 信号signal处理函数