• 本文介绍3个与网络编程有关的3个信号

一、SIGHUP信号处理

  • 信号产生的情景:

    • 1.如果终端接口检测到一个连接断开,则将此信号送给与该终端相关的控制进程(会话首进程)

      • 此信号被送给session结构中s_leader字段所指向的进程。仅当终端的CLOCAL标志没有设置时,在上述条件下才产生此信号(如果所连接的终端是本地的,则设置该终端的CLOCAL标志。它告诉终端驱动程序忽略所有调制解调器的状态行)
      • 注意:接到此信号的会话首进程可能在后台。这区别于由终端正常产生的几个信号(中断、退出和挂起),这些信号总是传递给前台进程组
    • 2.如果会话首进程终止,也产生此信号,在此情况下,此信号送给前台进程组的每一个进程
  • 程序对此信号的默认动作为终止程序
  • 通常用此信号通知守护进程再次读取它们的配置文件。选用SIGHUP的理由是,守护进程不会有控制终端,通常绝不会接收到这种信号。一个典型的例子就是xinetd超级服务程序(见下面的演示案例)

演示案例(xinetd超级服务程序)

  • xinetd程序在接收到SIGHUP信号之后将调用hard_reconfig函数,它循环读取/etc/xinetd.g/目录下的每个子配置文件,并检测其变化
  • 如果某个正在运行的子服务的配置文件被修改以停止服务,则xinetd主程序将给该子服务进程发送SIGTERM信号以结束它。如果某个子服务的配置文件被修改以开启服务,则xinetd将创建新的socket并将其绑定到该服务对应的端口上
  • 现在来分析xinetd处理SIGHUP信号的流程。下面是检测机器的环境:
    • 从ps的输出可以看出,xinetd创建子进程7442,它运行echo-stream内部服务
    • 从lsof输出来看,xinetd打开了一个管道。该管道的读端文件描述符的值是3,写端文件描述符的值是4(这个就是我们前面介绍的统一事件源)

  • 现在我们修改/etc/xinetd.d/目录下的部分配置文件,并给xinetd发送一个SIGHUP信号,操作如下:

  • 我们使用streace命令跟踪程序执行时调用的系统调用和接收到的信号。此处我们根据进程7438(即xinetd服务器程序),输出内容如下,每个部分用空行隔开,共4个部分:

    • 第一部分:描述程序接收到SIGHUP信号时,信号处理函数使用管道通知主程序该信号的到来。信号处理函数往文件描述符4(管道的写端)写入信号值1(SIGHUP信号),而主程序使用poll检测到文件描述符3(管道的读端)上有可读事件,就将管道上的数据读入
    • 第二部分:描述符了xinetd重新读取一个子配置文件的过程
    • 第三部分:描述了xinetd给子进程echo-stream(PID为7442)发送SIGTERM信号来终止该子进程,调用waitpid来等待子进程结束
    • 第四部分:描述了xinetd启动telnet服务的过程:创建一个流服务socket并将其绑定到端口23上,然后监听该端口

二、SIGPIPE信号处理

  • 信号产生的情景:

    • 如果在管道的读进程已终止时写管道,则产生此信号
    • 当类型为SOCK_STREAM的套接字已不再连接时,进程写该套接字也产生此信号
  • 程序对此信号的默认动作为终止程序
  • 引起SIGPIPE信号的写操作将设置errno为EPIPE
  • 信号处理:
    • 我们可以使用send函数的MSG_NOSIGNAL标志来禁止写操作触发SIGPIPE信号
    • 我们也可以根据errno值来判断管道或者socket连接的读端是否已经关闭
    • 我们也可以根据I/O复用系统来检测管道和socket连接的读端是否已经关闭。以poll为例,当管道的读端关闭时,写端文件描述符上的POLLHUP事件将被触发;当socket连接对对方关闭时,socket上的POLLRDHUP事件将被触发

三、SIGURG信号处理

  • 信号产生的情景:此信号通知进程已经发生了一个紧急情况。在网络连接上接到带外的数据时,可选择的产生此信号
  • 程序对此信号的默认动作为忽略此信号
  • 处理带外数据:在前面文章中(https://blog.csdn.net/qq_41453285/article/details/103126845),我们介绍了select在接收到带外数据时将返回,并向应用程序报告socket上的异常事件。此处我们可以使用SIGURG信号处理带外数据

演示案例(处理带外数据)

//sigurg.cpp
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <libgen.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>#define LISTEN_NUM  5
#define BUFFER_SIZE 1024static int client_fd; //客户端的fdvoid add_signal(int signal_no,void (*sig_handler)(int signal_no));void sig_handler(int signal_no);int main(int argc,char* argv[])
{    if(argc!=3){printf("usage:./%s [server ip] [server port]\n",basename(argv[1]));exit(EXIT_FAILURE);}const char* ip;int server_fd,port;ip=argv[1];port=atoi(argv[2]);//创建套接字if((server_fd=socket(AF_INET,SOCK_STREAM,0))==-1){perror("socket");exit(EXIT_FAILURE);}//初始化服务器地址struct sockaddr_in server_address;bzero(&server_address,sizeof(server_address));server_address.sin_family=AF_INET;server_address.sin_port=htons(port);if(inet_pton(AF_INET,ip,&server_address.sin_addr)==-1){perror("inet_pton");exit(EXIT_FAILURE);}//绑定服务端地址if(bind(server_fd,(struct sockaddr*)&server_address,sizeof(server_address))==-1){perror("bind");exit(EXIT_FAILURE);}//开启监听if(listen(server_fd,LISTEN_NUM)==-1){perror("listen");exit(EXIT_FAILURE);}//接受客户端连接struct sockaddr_in client_address;socklen_t client_address_len=sizeof(client_address);bzero(&client_address,sizeof(client_address));if((client_fd=accept(server_fd,(struct sockaddr*)&client_address,&client_address_len))==-1){perror("accept");exit(EXIT_FAILURE);}else{//添加SIGURG信号处理函数add_signal(SIGURG,sig_handler);//使用SIGURG之前,必须设置socket的宿主进程或进程组fcntl(client_fd,F_SETOWN,getpid());int recv_ret_value;char recv_buffer[BUFFER_SIZE];//接收普通数据while(1){bzero(recv_buffer,sizeof(recv_buffer));//接收数据recv_ret_value=recv(client_fd,recv_buffer,sizeof(recv_buffer-1),0);if(recv_ret_value<0){perror("recv");close(client_fd);close(server_fd);exit(EXIT_FAILURE);}else if(recv_ret_value==0){break;}else{printf("recv normal data:%s ,%d bytes\n",recv_buffer,recv_ret_value);}}close(client_fd);}close(server_fd);exit(EXIT_SUCCESS);
}void add_signal(int signal_no,void (*sig_handler)(int signal_no))
{struct sigaction act;act.sa_handler=sig_handler;sigemptyset(&act.sa_mask);act.sa_flags=0;//对信号进行处理sigaction(signal_no,&act,NULL);
}void sig_handler(int signal_no)
{//在这个信号处理函数中,我们接收带外数据int save_errno=errno;int recv_ret_value;char recv_buffer[BUFFER_SIZE];bzero(recv_buffer,sizeof(recv_buffer));//接收带外数据recv_ret_value=recv(client_fd,recv_buffer,sizeof(recv_buffer-1),0);printf("recv oob data:%s ,%d bytes\n",recv_buffer,recv_ret_value);errno=save_errno;
}
  • 测试程序:接下来我们用前面文章介绍过的一个可以发送带外数据的客户端程序(https://blog.csdn.net/qq_41453285/article/details/102984652)向这个服务端程序发送带外数据,然后测试是否是否可以收到带外数据,检测成功

Linux(程序设计):59---SIGHUP、SIGPIPE、SIGURG信号处理(附SIGURG信号处理普通数据与外带数据案例)相关推荐

  1. 视频教程-Linux程序设计从入门到实战-C/C++

    Linux程序设计从入门到实战 夏曹俊:南京捷帝科技有限公司创始人,南京大学计算机硕士毕业,有15年c++跨平台项目研发的经验,领导开发过大量的c++虚拟仿真,计算机视觉,嵌入式图像处理,云安全审计项 ...

  2. linux 编程中忽略SIGPIPE信号

    linux 编程中忽略SIGPIPE信号 SIGPIPE 简单来说,就是客户端程序向服务器端程序发送了消息,然后关闭客户端,服务器端返回消息的时候就会收到内核给的SIGPIPE信号. TCP的全双工信 ...

  3. Exam - Linux程序设计

    Linux考试重点 写在前面: Linux程序设计这门课确实能学到一些实用的东西.但是考试不敢恭维-感觉还是往年卷重要一点吧))) ​ 20届试卷 5道单选+文件锁类型并举例相关系统调用+内核和应用程 ...

  4. linux程序设计---序

    近段时间,一直在学习<Linux程序设计(第三版)>这本书.书中的知识点(个人认为是知识点)记作笔记,方便以后复习使用. 实验环境为:Ubuntu11.04 或者Ubuntu12.04,两 ...

  5. Linux程序设计实验项目六,《linux程序设计》实验教学大纲

    <linux程序设计>实验教学大纲 课程名称:Linux程序设计 课程编号:408412420408436407 适用专业:计算机科学与技术网络工程软件工程 总 学 分:3 总 学 时:4 ...

  6. linux程序设计项目报告,Linux程序设计实验报告大作业

    Linux程序设计实验报告大作业 实 验 报 告 课程名称: LINUX程序设计 学 院: 计算机学院 专 业: 软件工程 班 级: 14-3 姓 名: 张正锟 学 号: 201401061038 2 ...

  7. linux系统程序问题报告,Linux程序设计实验报告.docx

    Linux程序设计实验报告.docx Linux程序设计实验指导书实验类别课内实验 实验课程名称Linux程序设计实验室名称软件工程专业实验室 实验课程编号 000 总 学 时32 学 分 2 适用专 ...

  8. 读书笔记之:Linux程序设计(第4版)(ch1-7) [ 学如逆水行舟,不进则退 ]

    <Linux 程序设计>是一本非常好的书,内容很全面,并且对于给出的例子都进行了详细的讲解.并且是通过一个的小型的项目的来讲解的:开始是使用shell进行编程实现,然后逐步进行改进,使用C ...

  9. [Linux] 读书笔记之:Linux程序设计(第4版)(ch1-7) [ 学如逆水行舟,不进则退 ]...

    <Linux 程序设计>是一本非常好的书,内容很全面,并且对于给出的例子都进行了详细的讲解.并且是通过一个的小型的项目的来讲解的:开始是使用shell进行编程实现,然后逐步进行改进,使用C ...

最新文章

  1. 如何用Python实现超级玛丽的界面和状态机?
  2. 全国大学生智能车单车行进组中的单车改造飞轮安装方案参考
  3. 演示:标准ACL的配置、及使用技巧、和相关局限
  4. R语言读取出现 列的数目比列的名字要多的解决方法
  5. codeblocks常用配置
  6. 《机器学习》 梯度下降
  7. red hat 5 和 oracle
  8. Fedora 18 下安装 mplayer
  9. [CodeForces 1603C] Extreme Extension(贪心 + 数论分块优化dp)
  10. Python:递归输出斐波那契数列
  11. 微型计算机主机箱内的所有部件均由,计算机应用基础模拟题
  12. 手机虚拟摄像头_新游 | 打破次元壁障,《猪猪侠AR虚拟使命》现实约战,一切尽在创酷互动!...
  13. 以太坊开发入门,完整入门篇
  14. 网站快速收录-网站快速收录工具下载免费
  15. 直观理解Neural Tangent Kernel
  16. sanity测试_Sanity.io入门-您可以自定义的无头CMS
  17. 【IoT】硬件PM系列(三):硬件产品经理需要掌握的定价策略
  18. RMAN准备目录数据库
  19. 无监控、不运维。运维系统架构设计附带思维导图
  20. 深入浅出ModbusTcp

热门文章

  1. 安科瑞开口式剩余电流互感器在工业改造项目的应用-卓宋兰
  2. C语言实现大小写字母互换
  3. uevent 驱动_uevent机制
  4. 车内看车头正不正技巧_驾考科目二自动挡学车攻略小技巧。
  5. 一文速览 Dubbo 3.0
  6. 用cygwin下载安装ncview(windows 下安装ncview)
  7. Linux环境下 nginx配置按天生成日志
  8. 沉锂母液回收—含锂料液锂富集
  9. HDMI切换器方案|3进1出HDMI切换器|5进1出HDMI2.0切换器AG7111设计电路
  10. 【开箱】B.FRIENDit BAG01懒骨头沙发椅,让你尽情耍废!