织梦云端:网络信号原理的艺术解码

hello !大家好呀! 欢迎大家来到我的Linux高性能服务器编程系列之《织梦云端:网络信号原理的艺术解码》,在这篇文章中,你将会学习到网络信号原理以及应用,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!!

希望这篇文章能对你有所帮助9fe07955741149f3aabeb4f503cab15a.png,大家要是觉得我写的不错的话,那就点点免费的小爱心吧!1a2b6b564fe64bee9090c1ca15a449e3.png(注:这章对于高性能服务器的架构非常重要哟!!!)

03d6d5d7168e4ccb946ff0532d6eb8b9.gif         

 

目录

一. 什么是信号?

二. 信号的发送以及处理方式 

三.网络编程相关信号

四.统一信号事件源


一. 什么是信号?

在Linux网络编程中,“信号”(Signal)是操作系统用来通知进程某个事件已经发生的一种机制。信号是一种软件中断,它可以在任何时候发送给一个进程,使得该进程可以中断当前的执行,处理该信号,然后再回到原来的执行状态。

Linux系统中定义了许多信号,每个信号都有其特定的用途。例如:

  • SIGINT:通常在用户按下Ctrl+C时发出,用于中断程序的执行。
  • SIGCHLD:当一个子进程终止时,父进程会收到这个信号。
  • SIGALRM:定时器超时时发送。
  • SIGPIPE:在尝试写入一个没有读取器的管道或socket时发送。

在网络编程中,信号经常用于处理各种异步事件,比如:

  1. 处理子进程状态变化:当一个子进程改变其状态(比如终止或暂停)时,父进程会接收到SIGCHLD信号。
  2. 处理网络IO:在一些网络编程模型中,如使用select或poll,当IO准备好时,可以通过信号来通知应用程序。
  3. 定时器:使用setitimeralarm函数设置的定时器超时时,可以通过SIGALRM信号通知进程。

处理信号的方法主要有两种:

  • 信号处理函数:可以为特定的信号设置一个处理函数(handler),当该信号发生时,系统将调用这个函数。
  • 信号掩码:可以阻塞某些信号,使得它们在处理期间不被传递给进程。

信号是Linux系统编程中的一个重要部分,特别是在网络编程领域,因为它们提供了一种机制来响应异步事件,这对于构建高效和响应迅速的网络应用程序至关重要。

二. 信号的发送以及处理方式 

在Linux中,信号的发送和处理可以通过以下函数来完成:

  1. signal():用于设置一个信号的处理函数。
  2. raise():用于向当前进程发送一个信号。
  3. kill():用于向指定进程发送一个信号。
  4. sigaction():提供了一种更为复杂的方式来设置信号的处理函数,包括信号掩码。
  5. sigprocmask():用于设置信号掩码,从而阻塞或解阻塞特定的信号。
  6. sigpending():用于检查被阻塞的信号。
  7. sigsuspend():用于在阻塞信号集的基础上临时替换信号掩码,并暂停进程直到捕获到一个信号。
  1. signal()

    • 功能signal函数用于设置一个信号的处理函数。当指定信号被传递给进程时,系统将调用这个处理函数。
    • 原型void (*signal(int sig, void (*func)(int)))(int);
    • 参数
      • sig:要处理的信号编号。
      • func:信号处理函数,可以是SIG_IGN(忽略信号)、SIG_DFL(默认处理)或者一个自定义的函数指针。
    • 返回值:返回先前的信号处理函数的指针。
  2. raise()

    • 功能raise函数用于向当前进程发送一个信号。
    • 原型int raise(int sig);
    • 参数sig是要发送的信号的编号。
    • 返回值:成功时返回0,失败时返回非0值。
  3. kill()

    • 功能kill函数用于向指定进程发送一个信号。
    • 原型int kill(pid_t pid, int sig);
    • 参数
      • pid:目标进程的进程ID。如果pid大于0,信号将发送给进程ID为pid的进程;如果pid等于0,信号将发送给与当前进程同组的所有进程;如果pid小于-1,信号将发送给进程组ID为-pid的所有进程。
      • sig:要发送的信号的编号。
    • 返回值:成功时返回0,失败时返回-1。
  4. sigaction()

    • 功能sigaction函数提供了一种更为复杂的方式来设置信号的处理函数,包括信号掩码和信号处理时的行为。
    • 原型int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact);
    • 参数
      • sig:要处理的信号编号。
      • act:指向sigaction结构的指针,用于指定新的信号处理动作。
      • oldact:指向sigaction结构的指针,用于保存先前的信号处理动作。
    • 返回值:成功时返回0,失败时返回-1。
  5. sigprocmask()

    • 功能sigprocmask函数用于设置信号掩码,从而阻塞或解阻塞特定的信号。
    • 原型int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    • 参数
      • how:如何修改信号掩码。可以是SIG_BLOCK(添加到当前掩码)、SIG_UNBLOCK(从当前掩码中移除)或SIG_SETMASK(替换当前掩码)。
      • set:指向要添加或移除的信号集的指针。
      • oldset:指向保存当前信号掩码的指针。
    • 返回值:成功时返回0,失败时返回-1。
  6. sigpending()

    • 功能sigpending函数用于检查被阻塞的信号。
    • 原型int sigpending(sigset_t *set);
    • 参数set是一个指向sigset_t的指针,用于保存当前进程阻塞且待处理的信号集。
    • 返回值:成功时返回0,失败时返回-1。
  7. sigsuspend()

    • 功能sigsuspend函数用于在阻塞信号集的基础上临时替换信号掩码,并暂停进程直到捕获到一个信号。
    • 原型int sigsuspend(const sigset_t *mask);
    • 参数mask是一个指向sigset_t的指针,指定了临时的信号掩码。
    • 返回值:总是返回-1,并将errno设置为EINTR,表示函数被信号中断。

这些函数是Linux信号处理的基石,它们允许程序以可控的方式处理信号,确保程序的稳定性和安全性。在实际使用中,sigaction通常比signal更受欢迎,因为它提供了更多的灵活性和控制。

 接下来给一个简单例子演示:

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

// 信号处理函数
void handle_sigint(int sig) {
    printf("Caught signal %d\n", sig);
}

int main() {
    struct sigaction sa;

    // 设置信号处理函数
    sa.sa_handler = &handle_sigint;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);

    // 发送信号
    raise(SIGINT);

    // 主循环
    while (1) {
        printf("Hello, World!\n");
        sleep(1);
    }

    return 0;
}

在这个示例中,我们首先设置了一个信号处理函数handle_sigint来处理SIGINT信号。然后,我们使用sigaction函数来设置这个处理函数。接着,我们使用raise函数向当前进程发送了一个SIGINT信号。最后,程序进入一个循环,每隔一秒打印一条消息。 

三.网络编程相关信号

在网络编程中,信号通常用于处理异步事件,比如网络IO的读写就绪、连接请求、超时等。以下是一些在网络编程中常用的信号及相关函数和代码示例:

  1. SIGIO
    • 功能:当网络IO操作可以进行时,系统会发送SIGIO信号给进程。
    • 使用场景:用于异步通知网络IO事件,如数据到达或套接字可写。
    • 代码示例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>

void handle_sigio(int sig) {
    printf("Received SIGIO signal.\n");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = &handle_sigio;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGIO, &sa, NULL);

    // 将标准输入设置为非阻塞
    fcntl(STDIN_FILENO, F_SETFL, O_ASYNC | O_NONBLOCK);
    fcntl(STDIN_FILENO, F_SETOWN, getpid());

    while (1) {
        sleep(1); // 模拟程序的其他工作
    }

    return 0;
}

在这个示例中,我们为SIGIO信号设置了一个处理函数handle_sigio。然后,我们将标准输入设置为异步通知模式,并指定当前进程作为信号接收者。当标准输入有数据可读时,进程将收到SIGIO信号。

  1. SIGPIPE
    • 功能:当尝试向一个已经关闭的管道或网络连接写入数据时,系统会发送SIGPIPE信号给进程。
    • 使用场景:用于处理对端已经断开连接的情况。
    • 代码示例
#include <stdio.h>
#include <signal.h>

void handle_sigpipe(int sig) {
    printf("Received SIGPIPE signal.\n");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = &handle_sigpipe;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGPIPE, &sa, NULL);

    // 模拟网络连接的写入操作
    // ...

    return 0;
}

在这个示例中,我们为SIGPIPE信号设置了一个处理函数handle_sigpipe。当尝试向一个已经关闭的连接写入数据时,进程将收到SIGPIPE信号。

  1. SIGALRM
    • 功能:当设定的定时器超时时,系统会发送SIGALRM信号给进程。
    • 使用场景:用于实现超时机制,比如在网络请求中没有及时收到响应。
    • 代码示例
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handle_sigalrm(int sig) {
    printf("Received SIGALRM signal.\n");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = &handle_sigalrm;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGALRM, &sa, NULL);

    alarm(5); // 设置5秒的定时器

    while (1) {
        sleep(1); // 模拟程序的其他工作
    }

    return 0;
}

在这个示例中,我们为SIGALRM信号设置了一个处理函数handle_sigalrm。然后,我们使用alarm函数设置了5秒的定时器。当定时器超时时,进程将收到SIGALRM信号。

四.统一信号事件源

 

在服务器程序中,统一处理信号和I/O事件是指使用单一的事件循环来处理所有的异步事件,包括信号和I/O事件(如网络数据到达、连接请求等)。这种方法可以提高程序的响应性和效率,因为它避免了在多个地方处理不同类型的事件,从而简化了程序的结构。

为了实现这一点,通常需要使用特殊的系统调用或库,如selectpollepoll(在Linux中)或kqueue(在BSD系统中),这些系统调用允许程序同时监控多个文件描述符的I/O事件。然而,信号通常不能直接通过这些系统调用来监控。因此,需要将信号处理与I/O事件处理结合起来,通常的做法是在信号处理函数中设置一个全局标志,然后在主事件循环中检查这个标志。

以下是一个简单例子:

// 全局变量,用于标记信号是否发生
volatile sig_atomic_t got_sigio = 0;

void handle_sigio(int sig) {
    got_sigio = 1; // 设置信号发生标志
}

int main() {
    struct sigaction sa;
    fd_set readfds;
    int max_fd = 0;

    // 设置SIGIO信号的处理函数
    sa.sa_handler = &handle_sigio;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGIO, &sa, NULL);

    // 将标准输入设置为非阻塞,并指定当前进程作为信号接收者
    fcntl(STDIN_FILENO, F_SETFL, O_ASYNC | O_NONBLOCK);
    fcntl(STDIN_FILENO, F_SETOWN, getpid());

    // 主事件循环
    while (1) {
        FD_ZERO(&readfds);

        // 监控标准输入
        FD_SET(STDIN_FILENO, &readfds);
        max_fd = STDIN_FILENO;

        // 使用select监控I/O事件
        struct timeval timeout = {5, 0}; // 超时设置为5秒
        int ready = select(max_fd + 1, &readfds, NULL, NULL, &timeout);

        if (ready == -1) {
            perror("select");
            break;
        } else if (ready == 0) {
            printf("Timeout occurred.\n");
        } else {
            if (FD_ISSET(STDIN_FILENO, &readfds)) {
                // 处理标准输入的I/O事件
                char buffer[1024];
                ssize_t count = read(STDIN_FILENO, buffer, sizeof(buffer));
                if (count <= 0) {
                    break;
                }
                printf("Read from stdin: %.*s", (int)count, buffer);
            }
        }

        // 检查信号是否发生
        if (got_sigio) {
            printf("SIGIO received.\n");
            got_sigio = 0; // 重置信号发生标志
        }
    }

    return 0;
}

在这个示例中,我们使用select来监控标准输入的I/O事件,并设置了一个全局变量got_sigio来标记SIGIO信号是否发生。在信号处理函数handle_sigio中,我们只是设置了这个标志。在主事件循环中,我们首先使用select来等待I/O事件,然后在select返回后检查是否收到了SIGIO信号。如果收到了信号,我们就处理它,然后继续事件循环。

请注意,这个示例仅用于演示目的,实际应用中可能需要更复杂的逻辑来处理信号和I/O事件,尤其是在多线程或多进程的环境中。此外,select并不是处理大量文件描述符的最有效方法,对于高性能服务器,通常会选择使用epollkqueue

     好啦!到这里这篇文章就结束啦,关于实例代码中我写了很多注释,如果大家还有不懂得,可以评论区或者私信我都可以哦4d7d9707063b4d9c90ac2bca034b5705.png!! 感谢大家的阅读,我还会持续创造网络编程相关内容的,记得点点小爱心和关注哟!2cd0d6ee4ef84605933ed7c04d71cfef.jpeg  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【树莓派】yolov5 Lite,目标检测,行人检测入侵报警,摄像头绑定

延续之前的程序&#xff1a; https://qq742971636.blog.csdn.net/article/details/138172400 文章目录 播放声音pygame不出声音怎么办&#xff08;调节音量&#xff09;树莓派上的音乐播放器&#xff08;可选&#xff09;命令行直接放歌&#xff08;尝试放mp3歌曲&#xff09; …

数据结构-二叉搜索树(BST)

目录 什么是二叉搜索树 二叉搜索树的特性 (1)顺序性 (2)局限性 二叉搜索树的应用 二叉搜索树的操作 (1)查找节点 (2)插入节点 (3)删除节点 (4)中序遍历 什么是二叉搜索树 如图所示&#xff0c;二叉搜索树&#xff08;binary search tree&#xff09;满足以下条件。…

【Vivado那些事儿】使用 Python 提取 ILA 数据

ILA应该是调试AMD-Xilinx FPGA最常用的IP。 在调试中&#xff0c;我们希望 ILA 中的波形可以提供有关设计问题的所有信息&#xff0c;但情况并非如此。对于复杂的调试&#xff0c;我们还需要将 ILA 捕获的真实数据存储到可以进一步处理的文件中。根据放置 ILA 的位置&#xff0…

C语言阶段的题目解析

前言 我们C语言已经学习的差不多了&#xff0c;但是C语言之中存在的一些问题与难点我们还不一定能够又快又好地解决&#xff0c;为了夯实我们的基础&#xff0c;我们来练习几道稍微有点难度的C语言习题吧 例题一 题目 int main(void) {unsigned char i 7;int j 0;for (; i…

【PyTorch 实战3:YOLOv5检测模型】10min揭秘 YOLOv5 检测网络架构、工作原理以及pytorch代码实现(附代码实现!)

YOLOv5简介 YOLOv5&#xff08;You Only Look Once, Version 5&#xff09;是一种先进的目标检测模型&#xff0c;是YOLO系列的最新版本&#xff0c;由Ultralytics公司开发。该模型利用深度学习技术&#xff0c;能够在图像或视频中实时准确地检测出多个对象的位置及其类别&…

千锤百炼之每日算法(三)

题外话 不会再水了,先把算法任务完成! 正题 第一题 简写单词 规定一种对于复合词的简写方式为只保留每个组成单词的首字母,并将首字母大写后再连接在一起 比如“College English Test"可以简写成“CET",“Computer Science 可以简写为"CS"&#xff0c;I a…

【深度学习】【Lora训练1】StabelDiffusion,Lora训练过程,秋叶包,Linux,SDXL Lora训练

文章目录 一、环境搭建指南二、个性化安装流程三、启动应用四、打开web五、开始训练 19.27服务器 一、环境搭建指南 打造一个高效且友好的开发环境&#xff1a; 项目源码获取&#xff1a; 通过以下命令轻松克隆项目及所有子模块至您的Linux系统&#xff1a; git clone --recu…

《ElementUI 基础知识》el-tabs header 监听鼠标中键滚动时左右滑动(ElementPlus同样适用)

前言 收到需求&#xff0c;可监听 el-tabs 头在鼠标 hover 时。滑动鼠标中键&#xff0c;可左右滑动&#xff01; 效果 鼠标中键上下滑动时&#xff1b;向上滑&#xff0c;向左移动&#xff1b;向下滑&#xff0c;向右移动&#xff1b; 实现 代码56 - 60行&#xff0c;添加…

寝室快修|基于SprinBoot+vue的贵工程寝室快修小程序(源码+数据库+文档)

贵工程寝室快修目录 目录 基于SprinBootvue的贵工程寝室快修小程序 一、前言 二、系统设计 三、系统功能设计 1学生信息管理 2 在线报修管理 3公告信息管理 4论坛信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&a…

操作系统安全:安全审计,Windows系统日志详解,Windows事件ID汇总

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

C++深度解析教程笔记2

C深度解析教程笔记2 第3课 - 进化后的 const 分析实验-C与C的const区别实验-C与C的const区别&const作用域 第4课 - 布尔类型和引用小结 本文学习自狄泰软件学院 唐佐林老师的 C深度解析教程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 第3课 - 进化后…

Unity 递归实现数字不重复的排列组合

实现 private void Permutation(List<int> num, int leftIndex, List<string> strs) {if (leftIndex < num.Count){for (int rightIndex leftIndex; rightIndex < num.Count; rightIndex){Swap(num, leftIndex, rightIndex);Permutation(num, leftIndex 1…

HarmonyOS 鸿蒙下载三方依赖 ohpm环境搭建

前言 ohpm&#xff08;One Hundred Percent Mermaid &#xff09;是一个集成了Mermaid的命令工具&#xff0c;可以用于生成关系图、序列图、等各种图表。我们可以使用ohpm来生成漂亮且可读性强的图表。 本期教大家如何搭建ophm环境&#xff1a; 一、在DevEco Studio中&#…

前端可以掌握的nginx相关操作

一、前言&#xff1a; 在日常开发中&#xff0c;前端工程师可以把打好的前端包直接放到测试服务器上&#xff0c;自己再验证功能是否改好&#xff0c;这样可以提高开发效率&#xff0c;写篇笔记记录一下我个人用到的命令 二、使用的工具 用MobaXterm完成相关操作&#xff0c…

Vue3 + TS 项目实战 - 后台管理系统 - 按钮权限

前期回顾 网站的打赏 —— 新一代的思路-CSDN博客https://blog.csdn.net/m0_57904695/article/details/136704914?spm1001.2014.3001.5501 目录 &#x1f6a9; XX银行_系统管理_按钮权限控制_前端_提测单 项目信息 提测版本信息 功能列表 测试范围 测试环境 ✅ 步…

[paper note]代码生成评估模型-CodeBLEU原理分析

论文信息 论文标题&#xff1a;CodeBLEU: a Method for Automatic Evaluation of Code Synthesis 发表时间&#xff1a;2020年9月 论文原文&#xff1a;CodeBLEU: a Method for Automatic Evaluation of Code Synthesis 论文内容 摘要 评价指标对一个领域的发展起着至关重…

大厂常见算法50题-替换空格

专栏持续更新50道算法题&#xff0c;都是大厂高频算法题&#xff0c;建议关注, 一起巧‘背’算法! 文章目录 题目解法一 String类replace方法解法二 遍历替换总结 题目 解法一 String类replace方法 String类自带的replace&#xff0c;方法传入两个char类型的参数&#xff0c;分…

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测 目录 分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现CNN-GRU…

蓝牙低能耗安全连接 – 数值比较

除了 LE Legacy 配对之外&#xff0c;LE Secure Connections 是另一种配对选项。 LE 安全连接是蓝牙 v4.2 中引入的增强安全功能。它使用符合联邦信息处理标准 (FIPS) 的算法&#xff08;称为椭圆曲线 Diffie Hellman (ECDH)&#xff09;来生成密钥。对于 LE 安全连接&#xff…

【Stream流基础篇】Java中的函数、函数对象、函数接口和方法引用及转换

什么是函数 在数学中&#xff0c;函数是这样定义的&#xff1a;它是给定一个数集A&#xff0c;假设其中的元素为x&#xff0c;对A中的元素x施加对应法则f&#xff0c;记作f&#xff08;x&#xff09;&#xff0c;得到另一数集B&#xff0c;假设B中的元素为y&#xff0c;则y与x…