linux下的SIGHUP系统信号

对于SIGHUP信号的介绍

  在介绍SIGHUP信号之前,先来了解两个概念:进程组和会话。

进程组
  进程组就是一系列相互关联的进程集合,系统中的每一个进程也必须从属于某一个进程组;每个进程组中都会有一个唯一的 ID(process group id),简称 PGID;PGID 一般等同于进程组的创建进程的 Process ID,而这个进进程一般也会被称为进程组先导(process group leader),同一进程组中除了进程组先导外的其他进程都是其子进程;
  进程组的存在,方便了系统对多个相关进程执行某些统一的操作,例如,我们可以一次性发送一个信号量给同一进程组中的所有进程。

会话
  会话(session)是一个若干进程组的集合,同样的,系统中每一个进程组也都必须从属于某一个会话;一个会话只拥有最多一个控制终端(也可以没有),该终端为会话中所有进程组中的进程所共用。一个会话中前台进程组只会有一个,只有其中的进程才可以和控制终端进行交互;除了前台进程组外的进程组,都是后台进程组;和进程组先导类似,会话中也有会话先导(session leader)的概念,用来表示建立起到控制终端连接的进程。在拥有控制终端的会话中,session leader 也被称为控制进程(controlling process),一般来说控制进程也就是登入系统的 shell 进程(login shell);
  
  执行睡眠后台进程sleep 50 & 之后,通过 ps命令查看该进程及shell信息如上图:

PPID 指父进程 id;PID 指进程 id;PGID 指进程组 id
SID 指会话 id;TTY 指会话的控制终端设备;COMMAND 指进程所执行的命令
TPGID 指前台进程组的 PGID。

SIGHUP信号的触发及默认处理
  在对会话的概念有所了解之后,我们现在开始正式介绍一下SIGHUP信号,SIGHUP 信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联. 系统对SIGHUP信号的默认处理是终止收到该信号的进程。所以若程序中没有捕捉该信号,当收到该信号时,进程就会退出。
  
SIGHUP会在以下3种情况下被发送给相应的进程:
  1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程);
  2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程;
   3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。
  
  例如:在我们登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个 Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进 程组和后台有终端输出的进程就会中止。

此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。 比如xinetd超级服务程序。
  当xinetd程序在接收到SIGHUP信号之后调用hard_reconfig函数,它将循环读取/etc/xinetd.d/目录下的每个子配置文件,并检测其变化。如果某个正在运行的子服务的配置文件被修改以停止服务,则xinetd主进程讲给该子服务进程发送SIGTERM信号来结束它。如果某个子服务的配置文件被修改以开启服务,则xinetd将创建新的socket并将其绑定到该服务对应的端口上。

SIGPIPE
  在网络编程中,SIGPIPE这个信号是很常见的。当往一个写端关闭的管道或socket连接中连续写入数据时会引发SIGPIPE信号,引发SIGPIPE信号的写操作将设置errno为EPIPE。在TCP通信中,当通信的双方中的一方close一个连接时,若另一方接着发数据,根据TCP协议的规定,会收到一个RST响应报文,若再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不能再写入数据。

  此外,因为SIGPIPE信号的默认行为是结束进程,而我们绝对不希望因为写操作的错误而导致程序退出,尤其是作为服务器程序来说就更恶劣了。所以我们应该对这种信号加以处理,在这里,介绍两种处理SIGPIPE信号的方式:
  1 、给SIGPIPE设置SIG_IGN信号处理函数,忽略该信号:

signal(SIGPIPE, SIG_IGN);
1
  前文说过,引发SIGPIPE信号的写操作将设置errno为EPIPE,。所以,第二次往关闭的socket中写入数据时, 会返回-1, 同时errno置为EPIPE. 这样,便能知道对端已经关闭,然后进行相应处理,而不会导致整个进程退出.
  2、使用send函数的MSG_NOSIGNAL 标志来禁止写操作触发SIGPIPE信号。

send(sockfd , buf , size , MSG_NOSIGNAL);
1
   同样,我们可以根据send函数反馈的errno来判断socket的读端是否已经关闭。
   此外,我们也可以通过IO复用函数来检测管道和socket连接的读端是否已经关闭。以POLL为例,当socket连接被对方关闭时,socket上的POLLRDHUP事件将被触发。

SIGURG
  在介绍SIGURG信号之前,先来说说什么是带外数据。

带外数据
  带外数据用于迅速告知对方本端发生的重要的事件。它比普通的数据(带内数据)拥有更高的优先级,不论发送缓冲区中是否有排队等待发送的数据,它总是被立即发送。带外数据的传输可以使用一条独立的传输层连接,也可以映射到传输普通数据的连接中。实际应用中,带外数据是使用很少见,有,telnet和ftp等远程非活跃程序。
  UDP没有没有实现带外数据传输,TCP也没有真正的带外数据。不过TCP利用头部的紧急指针标志和紧急指针,为应用程序提供了一种紧急方式,含义和带外数据类似。TCP的紧急方式利用传输普通数据的连接来传输紧急数据。

SIGURG信号的作用
  内核通知应用程序带外数据到达的方式有两种:一种就是利用IO复用技术的系统调用(如select)在接受到带外数据时将返回,并向应用程序报告socket上的异常事件。
  另一种方法就是使用SIGURG信号。

若对服务器同时处理普通数据和带外数据感兴趣的话可以参考示例程序。

https://blog.csdn.net/z_ryan/article/details/80952498?utm_source=blogxgwz6

在介绍在网络编程中几个密切相关的函数:SIGPIPE,SIGURG、、、、、、

名称      默认动作            说明

  SIGHUP      终止进程      终端线路挂断

  SIGINT    终止进程      中断进程

  SIGQUIT   建立CORE文件  终止进程,并且生成core文件

  SIGILL    建立CORE文件        非法指令

  SIGTRAP   建立CORE文件        跟踪自陷

  SIGBUS    建立CORE文件        总线错误

  SIGSEGV   建立CORE文件        段非法错误

  SIGFPE    建立CORE文件        浮点异常

  SIGIOT    建立CORE文件        执行I/O自陷

  SIGKILL   终止进程      杀死进程

  SIGPIPE   终止进程      向一个没有读进程的管道写数据

  SIGALarm  终止进程      计时器到时

  SIGTERM   终止进程      软件终止信号

  SIGSTOP   停止进程      非终端来的停止信号

  SIGTSTP   停止进程      终端来的停止信号

  SIGCONT   忽略信号      继续执行一个停止的进程

  SIGURG    忽略信号      I/O紧急信号

  SIGIO     忽略信号      描述符上可以进行I/O

  SIGCHLD   忽略信号      当子进程停止或退出时通知父进程

  SIGTTOU   停止进程      后台进程写终端

  SIGTTIN   停止进程      后台进程读终端

  SIGXGPU   终止进程      CPU时限超时

  SIGXFSZ   终止进程      文件长度过长

  SIGWINCH  忽略信号      窗口大小发生变化

  SIGPROF   终止进程      统计分布图用计时器到时

  SIGUSR1   终止进程      用户定义信号1

  SIGUSR2   终止进程      用户定义信号2

  SIGVTALRM 终止进程      虚拟计时器到时

  1) SIGHUP 本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联.

  2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出

  3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号.

  4) SIGILL 执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号.

  5) SIGTRAP 由断点指令或其它trap指令产生. 由debugger使用.

  6) SIGABRT 程序自己发现错误并调用abort时产生.

  7) SIGIOT 在PDP-11上由iot指令产生, 在其它机器上和SIGABRT一样.

  8) SIGBUS 非法地址, 包括内存地址对齐(alignment)出错. eg: 访问一个四个字长的整数, 但其地址不是4的倍数.

  9) SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误.

  10) SIGKILL 用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略.

  11) SIGUSR1 留给用户使用

  12) SIGSEGV 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.

  13) SIGUSR2 留给用户使用

  14) SIGPIPE Broken pipe

  15) SIGALRM 时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.

  16) SIGTERM 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这个信号.

  17) SIGCHLD 子进程结束时, 父进程会收到这个信号.

  18) SIGCONT 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符.

posted @ 2019-12-16 20:06  konglingbin  阅读(11584)  评论(0编辑  收藏  举报