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

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  

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

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

相关文章

Elasticsearch:使用 MongoDB connector 同步数据到 Elasticsearch

MongoDB 是一个基于分布式文件存储的数据库。由 C 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。Elasticsearch 是一个高效强…

Windows Server 2019虚拟机安装

目录 第一步、准备工作 第二步、部署虚拟机 第三步、 Windows Server 2019系统启动配置 第一步、准备工作 下载Windows Server 2019系统镜像 官网下载地址&#xff1a;Windows Server 2019 | Microsoft Evaluation Center VMware Workstation 17下载地址&#xff1a; 链…

excel如何将多列数据转换为一列?

这个数据整理借用数据透视表也可以做到&#xff1a; 1.先将数据源的表头补齐&#xff0c;“姓名” 2.点击插入选项卡&#xff0c;数据透视表&#xff0c;在弹出对话框中&#xff0c;数据透视位置选择 现有工作表&#xff0c;&#xff08;实际使用时新建也没有问题&#xff09;…

Spring的基本应用

概述&#xff1a;Spring是由Rod Johnson组织开发的一个分层的java SE/EE一站式的轻量级开源框架&#xff0c;以IOC(控制反转)和AOP&#xff08;面向切面&#xff09;为核心&#xff0c;的开发模式。 注&#xff1a;喜欢的朋友可以关注公众号“JAVA学习课堂”系统学习相关技术&a…

Python自动化实战 —— 使用Selenium进行Web自动化!

为了完成一项重复的任务&#xff0c;你需要在网站上进行大量的点击和操作&#xff0c;每次都要浪费大量的时间和精力。Python的Selenium库就可以自动化完成这些任务。 在本篇文章中&#xff0c;我们将会介绍如何使用Python的Selenium库进行Web自动化&#xff0c;以及如何将它应…

学习和分析各种数据结构所要掌握的一个重要知识——CPU的缓存利用率(命中率)

什么是CPU缓存利用率&#xff08;命中率&#xff09;&#xff0c;我们首先要把内存搞清楚。 硬盘是什么&#xff0c;内存是什么&#xff0c;高速缓存是什么&#xff0c;寄存器又是什么&#xff1f; 我们要储存数据就要运用到上面的东西。首先里面的硬盘是可以无电存储的&#…

快速修改禅道系统的管理员密码

目录 通过 web 登录页面忘记密码&#xff08;推荐&#xff09;通过数据库&#xff0c;修改 zt_user 表 通过 web 登录页面忘记密码&#xff08;推荐&#xff09; 只能修改管理员密码。 打开禅道地址&#xff0c;点击忘记密码会显示下面的页面&#xff1a; 根据提示在服务器的相…

【busybox记录】【shell指令】shuf

目录 内容来源&#xff1a; 【GUN】【shuf】指令介绍 【busybox】【shuf】指令介绍 【linux】【shuf】指令介绍 使用示例&#xff1a; 打乱内容 - 默认输出 打乱内容 - 最多输出n行 打乱内容 - 将输出写入文件 打乱内容 - 重复输出 打乱内容 - 打乱本条指令的参数 打…

并发控制互斥笔记

整理总结自蒋炎岩老师的b站课程&#xff0c;https://jyywiki.cn/OS/2022/index.html 多处理器系统中数据的一致性和互斥访问 所有的CPU的一级缓存都是连着的&#xff0c;如果是多个CPU的话&#xff0c;用在内存中放置标志位&#xff0c;来保证对当前内容的原子性读取&#xff0…

第六代移动通信介绍、无线网络类型、白皮书

关于6G 即第六代移动通信的介绍&#xff0c; 图解通信原理与案例分析-30&#xff1a;6G-天地互联、陆海空一体、全空间覆盖的超宽带移动通信系统_6g原理-CSDN博客文章浏览阅读1.7w次&#xff0c;点赞34次&#xff0c;收藏165次。6G 即第六代移动通信&#xff0c;6G 将在5G 的基…

经常发文章的你是否想过定时发布是咋实现的?

前言 可乐他们团队最近在做一个文章社区平台,由于人手不够,前后端都是由前端同学来写。后端使用 nest 来实现。 某一天周五下午,可乐正在快乐摸鱼,想到周末即将来临,十分开心。然而,产品突然找到了他,说道:可乐,我们要做一个文章定时发布功能。 现在我先为你解释一…

「代码与养生」 :当下程序员的养生指南

前言 众所周知&#xff0c;程序员是死的比较快的一类人。因为天天加班、睡眠不足、久坐不动、长时间面对电子屏幕辐射、长时间高强度用脑等不好避免的问题。因此&#xff0c;要想活的时间长一点&#xff0c;就要多了解一些养生之道 下面&#xff0c;根据个人看的一些博客、书…

表空间的创建

目录 表空间创建的语法 表空间创建的例子 创建一个永久性表空间&#xff0c;设置表空间初始大小为100MB&#xff0c;自动扩展为 100MB&#xff0c;无最大大小限制&#xff0c;并且该表空间为在线状态&#xff0c;产生日志 创建一个永久性表空间&#xff0c;通过本地化管理方…

面向新手在无人机竞速场景下的飞行辅助系统——浙大 FAST-Lab 高飞团队 ICRA 论文三项 Best Paper 入围

恭喜浙江大学 FAST-Lab 钟宇航同学的论文 A Trajectory-based Flight Assistive System for Novice Pilots in Drone Racing Scenario 顺利发表 ICRA 2024&#xff0c;并同时入选三项 Finalist&#xff1a; the IEEE ICRA Best Conference Paper Awardthe IEEE ICRA Best Pape…

深入理解Java虚拟机(JVM)

引言&#xff1a; Java虚拟机&#xff08;JVM&#xff09;是Java平台的核心组件&#xff0c;它负责将Java字节码转换成平台特定的机器指令&#xff0c;并在相应的硬件和操作系统上执行。JVM的引入使得Java语言具有“一次编写&#xff0c;到处运行”的跨平台特性。本文将深入探…

ICC2:optimize_routability

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 在postroute阶段,一些pin access引起的绕线问题,通常以end of line和short/spacing的形式扎堆出现,总量兴许不多,但是反复绕线仍难解决,返回preplace去设置keepout margin或placement label又得…

绘画作品3d数字云展厅提升大众的艺术鉴赏和欣赏能力

3D虚拟展厅作为未来艺术的展示途径&#xff0c;正逐渐成为文化创意产业蓬勃发展的重要引擎。这一创新形式不仅打破了传统艺术展览的局限性&#xff0c;更以其独特的魅力吸引着全球观众的目光。 3D虚拟艺术品展厅以其独特的魅力&#xff0c;助力提升大众的艺术鉴赏和欣赏能力。观…

什么是多模态大模型,有了大模型,为什么还要多模态大模型?

随着人工智能技术的愈演愈烈&#xff0c;其技术可以说是日新月异&#xff0c;每隔一段时间就会有新的技术和理念被创造出来&#xff1b;而多模态大模型也是其中之一。 什么是多模态 想弄明白什么是多模态大模型&#xff0c;那么首先就要弄明白什么是多模态。 简单来说&#x…

红海云OA存在任意文件上传漏洞【附poc】

漏洞复现 1、fofa poc见文末 body"RedseaPlatform" 打开burp进行抓包发送到repeater&#xff0c;如下图所示&#xff1a; 打入poc&#xff08;文末获取&#xff09;&#xff0c;成功上传。 「你即将失去如下所有学习变强机会」 学习效率低&#xff0c;学不到实战内…

【Linux】基础命令

常用命令及参数&#xff1a;dir表示文件夹&#xff0c;file表示文件&#xff08;file可表示其他目录下的文件&#xff09; pwd命令&#xff1b;查看当前所属文件夹&#xff08;print working directory&#xff09; ls [选项] dir&#xff1b;查看当前、指定文件夹目录内容&am…