Linux信号的基本概念及处理方法

网络程序要处理的三类事件:IO事件、信号事件、定时器事件。

1. 信号的概念:

1.1 谁会产生信号:

用户、系统、进程,都会产生信号,信号就是由用户/系统/进程 发给另一个进程的信息,用于通知进程某个状态的改变或者系统异常。

1.2 如何对待信号:

服务器程序必须处理一些信号(至少要忽略),因为如果不人为注册处理函数,系统会按照默认方式对一些信号进行处理,而很多信号的默认处理方式就是终止进程,对于服务器来说我们显然不想让它终止。

一旦有信号产生,用户进程对信号的处理方式有三种:

  1. 执行默认操作:
    Linux对每种信号都规定了默认的操作,例如SIGTERM信号表示终止进程等;
  2. 捕获信号:
    可以为信号定义一个信号处理函数,当信号发生时,程序就会执行相应的处理函数;
  3. 忽略信号:
    如果不希望处理某些信号,就可以忽略该信号,不做任何处理。
    有两个信号是应用进程无法捕获和忽略的:
    SIGKILL(9) 和 SIGSTOP(19),它们用于在任何时候中断或结束某一进程。

2. 信号处理函数:

2.1 发送信号:

我们不能控制系统去给进程发送信号,但可以通过调用 kill 函数在一个进程中给另一个进程手动的发送信号:

//kill -- send signal to a process

#include <signal>

int kill(pid_t pid, int sig);

参数:
pid表示要将信号发送给哪些进程:
当 pid > 0 时,只将信号发送给pid指定的进程;
当 pid = 0 时,(如果发送者进程有权限的话)将信号发送给发送者进程所在进程组内的所有进程;
当 pid < 0 时,(如果发送者进程有权限的话)将信号发送给系统内所有的进程。

2.2 sigaction() 函数:

函数原型:

//sigaction -- software signal facilities

#include <signal.h>

struct sigaction {
    union       __sigaction_u  __sigaction_u;		//指定信号处理函数
    sigset_t    sa_mask;							//设置信号掩码,在sa_handler信号处理函数运行期间进程会屏蔽掉sa_mask指定的信号,防止信号处理函数被打断
    int         sa_flags;							//设置程序接收到信号时的行为,例如 SA_RESTART,重新调用被该信号中止的系统调用
};

union __sigaction_u {
    void (*__sa_handler)(int);
    void (*__sa_sigaction)(int, siginfo_t *, void *);
};

#define  sa_handler    __sigaction_u.__sa_handler
#define  sa_sigaction  __sigaction_u.__sa_sigaction

int sigaction(int sig, const struct sigaction *restrict act, 
			  		   struct sigaction *restrict oact)

------

//对于 sigset_t sa_mask :
typedef struct {
    unsigned long int __val[SIGSET_NWORDS];
} _sigset_t;

int sigemptyset(sigset_t *set);				//清空信号集
int sigfillset(sigset_t *set);				//设置信号集中所有信号
int sigaddset(sigset_t *set, int signo);	//将signo添加进set
int sigdelset(sigset_t *set, int signo);	//将signo从set中移除
ing sigismember(sigset_t *set, int signo);	//判断signo是否在set中

函数 sigaction() 可以理解为 “信号安装函数”,用来向系统中“安装”一个对应某信号的处理回调函数。

2.3 signal() 函数:

函数原型:

//signal -- simplified software signal facilities

#include <signal.h>

void (*signal(int sig, void (*func)(int)))(int);

signal()函数这种方式比较简单粗暴,相比于sigaction()函数,signal()函数只是注册了 sa_handler处理函数,sa_mask和sa_flags均无法指定。

关于signal()函数的参数:
sig:表示函数要处理的信号;
func:对应信号处理的三种方式:
(1)如果是使用默认方式处理,func的值必须是 SIG_DFL
(2)如果是忽略信号,func的值必须是 SIG_IGN
(3)如果是捕获信号并注册处理函数,func的值是用户自定义的回调函数。

3. 实际应用:

signal(SIGCHLD, SIG_DFL);		//使用该信号默认的处理方式
signal(SIGPIPE, SIG_IGN);		//收到此信号后忽略该信号

signal(SIGINT, Stop);			//捕获信号,并注册信号处理函数Stop
signal(SIGTERM, Stop);
signal(SIGUSR1, signal_handler_usr1);
signal(SIGUSR2, signal_handler_usr2);
signal(SIGHUP, signal_handler_hup);

------

void Stop(int sig_no) {
    log("recieve signal: %d\n", sig_no);
    switch(sig_no) {
		case SIGINT:
		case SIGTERM:
		case SIGQUIT:
			doQuitJob();
			_exit(0);
			break;
		default:
			cout << "unknown signal" << endl;
			_exit(0);
	}
}

static void signal_handler_user1(int sig_no) {
    if(sig_no == SIGUSR1) {
        log("recieve SIGUSR1");
        g_up_msg_total_cnt = 0;
        g_up_msg_miss_cnt = 0;
    }
}

static void signal_handler_user2(int sig_no) {
    if(sig_no == SIGUSR2) {
        log("recieve SIGUSR2");
        g_log_msg_toggle = !g_log_msg_toggle;
    }
}

static void signal_hanlder_hup(int sig_no) {
    if(sig_no == SIGHUP) {
        log("recieve SIGHUP");
        exit(0);
    }
}

4. 网络编程中常见的几个信号:

Linux系统中提供的信号:(可在命令行中使用 kill -l 命令查看)
请添加图片描述

摘自 man signal 手册:

No    Name         Default Action       Description
1     SIGHUP       terminate process    terminal line hangup
2     SIGINT       terminate process    interrupt program
3     SIGQUIT      create core image    quit program
4     SIGILL       create core image    illegal instruction
5     SIGTRAP      create core image    trace trap
6     SIGABRT      create core image    abort program (formerly SIGIOT)
7     SIGEMT       create core image    emulate instruction executed
8     SIGFPE       create core image    floating-point exception
9     SIGKILL      terminate process    kill program
10    SIGBUS       create core image    bus error
11    SIGSEGV      create core image    segmentation violation
12    SIGSYS       create core image    non-existent system call invoked
13    SIGPIPE      terminate process    write on a pipe with no reader
14    SIGALRM      terminate process    real-time timer expired
15    SIGTERM      terminate process    software termination signal
16    SIGURG       discard signal       urgent condition present on socket
17    SIGSTOP      stop process         stop (cannot be caught or ignored)
18    SIGTSTP      stop process         stop signal generated from keyboard
19    SIGCONT      discard signal       continue after stop
20    SIGCHLD      discard signal       child status has changed
21    SIGTTIN      stop process         background read attempted from control terminal
22    SIGTTOU      stop process         background write attempted to control terminal
23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
28    SIGWINCH     discard signal       Window size change
29    SIGINFO      discard signal       status request from keyboard
30    SIGUSR1      terminate process    User defined signal 1
31    SIGUSR2      terminate process    User defined signal 2

4.1 SIGINT(2)、SIGTERM(15)、SIGKILL(9) 的区别:

三者都是结束/终止进程运行。

SIGINT与 Ctrl+C 关联,SIGTERM和SIGKILL没有与任何控制字符关联;
SIGINT只能结束前台进程。

SIGTERM可以被阻塞、处理和忽略,SIGKILL不可以;

KILL命令默认的不带参数发送的信号就是 SIGTERM,让程序可以捕获并优雅的退出。但是由于SIGTERM可以被阻塞,所以当进程不能被结束时,需要使用SIGKILL强制进程退出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值