Linux高性能服务器编程第十章信号

信号是由用户、系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常。

  • 对于前台进程,用户可以通过输入特殊的终端字符来给他发送信号,比如ctrl c
  • 系统异常 比如浮点异常和非法内存段访问
  • 系统状态变化 比如定时器发出的信号
  • kill命令或调用kill函数

概述

发送信号

Linux中一个进程给其他进程发送信号的API函数是kill

1
2
3
#include <sysitypes.h>
#include <signal.h>
int kill(pid_t pid, int sig ) ;

pid指的是目标进程,sig指的是信号。

image-20231110092818639

信号处理方式

目标进程收到信号时,需要定义一个接收函数来处理,原型如下:

1
2
#include <signal.h>
typedef void ( *.__sighandler_t) ( int );

Linux信号

与网络编程比较相关的有SIGHUP、SIGPIPE、SIGURG

信号函数

signal系统调用

要为一个信号设置处理函数,可以使用下面的signal系统调用:

1
2
#include <signal.h>
_sighandler_t signal ( int sig,_sighandler_t _handler )

sig参数指出要捕获的信号类型,_handler参数是_sighandler_t类型的函数指针,用于指定信号sig的处理函数

sigaction系统调用

sigaction更健壮:

1
2
# include <signal.h>
int sigaction( int sig, const struct sigaction* act,struct sigaction* oact );

act指定新的信号处理方式,oact输出之前的处理方式

信号集

信号集函数

1
2
3
4
5
#include <bits/ sigset.h>
# define __SIGSET_NWORDS (1024 / ( 8 * sizeof (unsigned long int) ) )
typedef struct{
unsigned long int __val [_SIGSET_NWORDS ];
}_sigset_t;

由该定义可见,sigset_t实际上是一个长整型数组,数组的每个元素的每个位表示一个信号。这种定义方式和文件描述符集 fd_set类似。Linux提供了如下一组函数来设置、修改、删除和查询信号集:

1
2
3
4
5
6
7
8
9
10
11
#include <signal.h>
int sigemptyset isigset_t* _set)
/*清空信号集*/
int sigflllset (sigset_t * _set)
/*在信号集中设置所有信号*/
int sigaddset (sigset_t* _set, int _signo)
/*将信号_signo添加至信号集中*/
int sigdelset (sigset_t* _set, int _signo)
/*将信号_signo从信号集中删除*/
int sigismember (_const sigset_t* _set,int _signo)
/*测试_signo是否在信号集中*/

网络编程相关信号

SIGHUP

当挂起进程的控制终端时,SIGHUP信号将被触发

SIGPIPE

默认情况下,往一个读端关闭的管道或socket连接中写数据将引发SIGPIPE信号,我们需要处理该信号,默认行为是结束进程,但我们不希望因为错误的写操作导致程序退出