【TCP/IP】多进程服务器的实现(进阶) - 信号处理及signal、sigaction函数

news2025/1/24 1:01:00

目录

信号

signal函数

sigaction函数

尝试用信号来处理僵尸进程


        我们在之前学习了如何处理“僵尸进程”,但也会有疑问:调用wait和waitpid函数时我们关注的始终是在子进程上,那么父进程上的管控(对于子进程)该如何实现呢?这就引出了接下来讲的内容——信号处理。

信号

        信号这个概念大家应该不陌生,诸如汽车的鸣笛、闹钟的响铃等,这些都是信号,用以告诉人们某件事情的发生。而在计算机中,同样有这个概念。在编程上常用信号来对接收到的某些数据或者指令做出与之对应的响应处理。

signal函数

        让我们先来看看<signal.h>库中的signal函数,其结构如下:

#include <signal.h>

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


// 为了在产生信号时调用,返回之前注册的函数指针。

// 函数概念:名为signal的返回类型为void型函数指针的,带有一个int参数的函数
// 参数 int signo, void (* func)(int)
// 返回类型:参数为int型,返回void型函数指针。

        signo参数用来标记触发的条件,func则为将要调用的函数的指针。与参数所相关的宏有:

  • SIGALRM: 按照已通过调用alarm函数注册的时间为信号点。
  • SIGINT: 输入CTRL+C暂停时为信号点
  • SIGCHILD: 子进程终止时为信号点。

补充:

        alarm函数的用法及意义如下:

#include <unistd.h>

unsigned int alarm (unsigned int seconds);

// 返回 以秒为单位 的,距 SIGALRM 信号发生时所剩余的时间

        其中 seconds 参数用以传入欲设定的alarm的周期(以s为单位)。若传递0至变量中,则意味着将会取消对SIGALRM信号的预约。同时,若未指定该产生信号所对应的处理函数时,则该进程将被终止。

        接下来,让我们尝试来编写 SIGALRM 和 SIGINT 两种事件下的验证demo吧。

singal.cpp

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void alarmEvent(int sig) //包括下面的keyEvent,这类函数被称为信号处理器(Handler)
{
    if (sig == SIGALRM)
    {
        printf("Time out!\n");
    }

    alarm(2);
}

void keyEvent(int sig)
{
    if (sig == SIGINT)
    {
        printf("\nCTRL+C pressed\n");
    }
}

int main(int argc, char *argv[])
{
    //注册:设置SIGGALRM为触发条件,调用alarmEvent函数
    signal(SIGALRM, alarmEvent); 
    //注册:设置SIGINT为触发条件,调用keyEvent函数
    signal(SIGINT, keyEvent);

    //设置时钟周期为2s
    alarm(2); 

    for (size_t i = 0; i < 5; i++)
    {
        printf("Wait for an event to occur...\n");
        sleep(50);  //实际操作上无法休眠50s
    }

    return 0;
}

        运行结果:

        验证完毕。

        Q:为什么程序在实际运行上,没有感受到在等待事件发生后的50s延迟呢?

        A:信号在响应时,尽管存在有阻塞态的进程,但操作系统为了调用信号处理器,会强制唤醒进行阻塞态(sleep中的)进程,并且该进程一旦被唤醒,将不会在进入睡眠状态,因此在操作上,我们并不会感受到会有长达50s的延迟。

sigaction函数

        sigaction算是对signal函数的升级,能够更好地支持不同的操作系统(signal函数在不同的操作系统中用法和效果可能会不同)。

        接下来让我们来看下这个函数长什么样:

#include <signal.h>

int sigaction(int signo , const struct sigaction * act , struct sigaction *
oldact) ;

// 成功时退回0,失败时退回-1。

/* 参数含义 */

// signo:与signal函数相同,传递信号信息
// act:对应第一个参数的信号处理函数
// oldact:通过此参数获取之前注册的信号处理函数指针,不需要时则传递0。

        对于sigaction,它的结构体定义如下:

 //结构体做了简化,实际上其中一些变量用宏和typedef做了进一步封装

 struct sigaction
    {
        void (*sa_handler)(int);
        sigset_t sa_mask;
        int sa_flags;
        void (*sa_restorer)(void);
    };

        参数意义可以参考以下: 

  • sa_handler:用以保存信号处理函数的指针值
  • sa_mask:需要滤除的附加信号集,省略
  • sa_flags:特殊标记符,省略
  • sa_restorer:欲重置的(信号)处理器,省略

        OK,让我们编写一个实例来验证这个函数的功能

sigaction.cpp

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void alarmEvent(int sig)
{
    if (sig == SIGALRM)
    {
        printf("Time out!\n");
    }
    alarm(2);
}

int main(int argc, char *argv[])
{
    //声明sigaction结构体变量act
    struct sigaction act;
    //将信号处理函数存入结构体中
    act.sa_handler = alarmEvent;
    //将sa_mask成员的所有位初始化为0
    sigemptyset(&act.sa_mask);
    //将sa_flags成员同样初始化为0
    act.sa_flags = 0;
    //注册:触发条件为SIGALARM,调用act信号处理器中的信息
    sigaction(SIGALRM, &act, 0);

    alarm(2);

    for (size_t i = 0; i < 5; i++)
    {
        printf("Wait for an event to occur...\n");
        sleep(50);
    }

    return 0;
}

        运行结果:

        结果验证了之前的想法。

尝试用信号来处理僵尸进程

        当我们掌握signal、sigaction两个函数后,便可更好地去管控父、子进程了。在之前我们采用的是wait、waitpid函数来销毁僵尸进程。接下来,请大家尝试一下用信号来消灭“僵尸进程”吧!

        欢迎大家在评论区贴出你们的代码~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/632509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32——05-按键、时钟控制、中断复位 点亮LED灯

如何点亮一颗LED灯 编程实现点灯 常用的 GPIO HAL 库函数&#xff1a; void HAL_GPIO_Init ( GPIO_TypeDef * GPIOx , GPIO_InitTypeDef * GPIO_Init ); void HAL_GPIO_WritePin ( GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin , GPIO_PinState PinState ); void HAL_GPIO_Togg…

chatgpt赋能python:Python如何创建新项目

Python如何创建新项目 Python已经成为了全球最受欢迎的编程语言之一。如果您是一个有经验的Python工程师&#xff0c;您可能已经知道如何在命令行上创建新项目。但是&#xff0c;如果您是一个新手或初学者&#xff0c;您可能需要一些指导来开始创建新的项目。在本篇文章中&…

Vue中如何进行样式绑定?

Vue中如何进行样式绑定&#xff1f; 在Vue中&#xff0c;我们可以很方便地进行样式绑定。样式绑定是将CSS样式与Vue组件中的数据进行关联的一种技术。通过样式绑定&#xff0c;我们可以根据组件的状态动态地修改其外观。本文将介绍Vue中的样式绑定&#xff0c;包括类绑定、内联…

chatgpt赋能python:Python如何进行升序排列?

Python如何进行升序排列&#xff1f; Python是一门广泛应用于Web开发、数据科学、人工智能、机器学习等领域的编程语言。在这个快速发展的世界中&#xff0c;如何高效地排序数据是非常重要的。本文将介绍Python中如何进行升序排序。 基本排序方法 Python提供了一个内置函数s…

Vue 中的列表渲染

Vue 中的列表渲染 在 Vue 中&#xff0c;列表渲染是非常常见的操作。它允许我们将一个数组中的数据渲染为一个列表&#xff0c;从而实现数据的展示和交互。在本文中&#xff0c;我们将探讨 Vue 中的列表渲染的基本原理和用法&#xff0c;并给出一些实例代码来帮助读者更好地理…

【模块三:职业成长】38|能力维度三:如何提升解决跨领域冲突的能力?

你好&#xff0c;我是郭东白。今天我们来讨论架构师核心能力的第三个层次——解决跨领域冲突。 上节课我们讲了从程序员到兼职架构师的跨越&#xff0c;也就是如何搭建解决横向问题的能力。 不过&#xff0c;在兼职架构师这个角色中&#xff0c;架构能力是一个加分项&#xff…

chatgpt赋能python:如何使用Python升序排列一个列表?

如何使用Python升序排列一个列表&#xff1f; 在Python编程中&#xff0c;我们经常需要对列表进行排序。列表排序是一种常见的操作&#xff0c;可以帮助我们对数据进行分析和管理。在这篇文章中&#xff0c;我们将学习如何使用Python对一个列表进行升序排列。 什么是升序排列…

时间同步/集群时间同步/在线/离线

目录 一、能够连接外网 二、集群不能连接外网--同步其它服务器时间 一、能够连接外网 1.介绍ntp时间协议 NTP&#xff08;Network Time Protocol&#xff09;网络时间协议&#xff0c;是用来使计算机时间同步的一种协议&#xff0c;它可以使计算机对其服务器或时钟源做同步…

【python】【Word】用正则表达式匹配正文中的标题(未使用样式)并通过win32com指定相应样式

标题的格式 二级标题&#xff1a; 数字.数字. 文字 三级标题&#xff1a;数字.数字.数字 文字 python代码 使用方法 只保留一个需要应用的WORD文档运行程序&#xff0c;逐行匹配 使用效果 代码 import win32com.client import redef compile_change_Word_titlestyle():#…

shell脚本语句控制命令(exit、break、continue)

一、exit exit用于直接退出shell脚本程序并返回状态码&#xff08;状态码可在执行命令执行后用$&#xff1f;查看&#xff09; 如果不在exit后添加状态码&#xff0c;会默认返回最后一条命令执行后的状态码 exit 加状态码&#xff0c;代表退出程序并向系统指定状态码 状态码…

基于zinx的go tcp通信案例

基于zinx的go tcp通信示例 一、zinx简介:(https://gitee.com/Aceld/zinx/) Zinx是一个基于Golang的轻量级tcp服务框架&#xff0c;根据官方的定位&#xff0c;zinx是在游戏领域或者其他长链接的领域的轻量级企业框架&#xff0c;其使用简单&#xff0c;性能高效&#xff0c;能…

Baumer工业相机堡盟工业相机如何使用BGAPISDK的相机图像时间戳计算运行时间以及时间差(C#)

Baumer工业相机堡盟工业相机如何使用BGAPISDK的相机图像时间戳计算运行时间以及时间差&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机BGAPI SDK和图像时间戳的技术背景Baumer工业相机使用BGAPISDK控制相机数据流的方式1.引用合适的类文件2.使用BGAPISDK获取时间戳的…

Vue中如何进行条件渲染

Vue中如何进行条件渲染 Vue是一款流行的前端框架&#xff0c;它提供了许多方便的功能来处理数据和视图。其中一个非常有用的功能是条件渲染。条件渲染可以根据条件来控制视图的显示和隐藏。在本文中&#xff0c;我们将介绍Vue中如何进行条件渲染&#xff0c;并提供一些示例代码…

异常数据检测 | Python实现k-means时间序列异常数据检测

文章目录 文章概述模型描述源码分享学习小结文章概述 异常数据检测 | Python实现k-means时间序列异常数据检测 模型描述 k-means是一种广泛使用的聚类算法。它创建了k个具有相似特性的数据组。不属于这些组的数据实例可能会被标记为异常。在我们开始k-means聚类之前,我们使用e…

spring.expression 随笔0 概述

0. 我只是个普通码农&#xff0c;不值得挽留 Spring SpEL表达式的使用 常见的应用场景:分布式锁的切面借助SpEL来构建key 比较另类的的应用场景:动态校验 个人感觉可以用作控制程序的走向&#xff0c;除此之外&#xff0c;spring的一些模块的自动配置类&#xff0c;也会在Cond…

chatgpt赋能python:Python如何判断输入数据类型

Python如何判断输入数据类型 Python是一种动态类型语言&#xff0c;它可以在运行时自动识别数据的类型。但是&#xff0c;有时候我们需要在代码中判断输入数据的类型&#xff0c;以便进行相应的操作。 判断数据类型的内置函数 Python有一些内置函数可以用于判断数据类型&…

仿滴滴打车百度地图定位查找附近出租车或门店信息

前端vue仿滴滴打车百度地图定位查找附近出租车或门店信息, 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id12982 效果图如下: # #### 使用方法 使用方法 #安装vue-baidu-map插件 npm install vue-baidu-map --save <!-- center: 地图中…

蓝牙耳机可以戴着游泳吗?推荐四款可以游泳的游泳耳机

今年的夏天格外炎热&#xff0c;热衷于户外运动的人们也开始转换健身方式&#xff0c;游泳作为一项锻炼全身又祛暑清凉的运动&#xff0c;自然成为了最佳选择&#xff0c;相信大多数人跟我一样在运动时都离不开耳机&#xff0c;而游泳需要和水接触&#xff0c;这也导致了我所有…

SpringBoot+Mybatis+Thymeleaf实现的物资管理系统

本系统具体使用的技术是&#xff1a;后端使用SpringBootMybatis&#xff0c;前端使用了Thymeleaf框架&#xff0c;数据库使用的是MySql 8.0。开发工具使用的是IDEA。 本系统前端是使用了前辈的管理系统模板&#xff0c;具体的系统模块功能如下图所示&#xff1a; 一、系统首页…

chatgpt赋能python:Python如何删除之前的内容

Python如何删除之前的内容 在Python编程中&#xff0c;删除之前输入或者生成的内容是一个常见的需求。本文将介绍如何在Python中删除之前的内容以及相关的技巧和方法。 为什么需要删除之前的内容&#xff1f; 在Python编程中&#xff0c;我们有时需要重新输入命令或代码段&a…