《Linux C编程实战》笔记:信号的发送

信号的发送主要由函数kill、raise、sigqueue、alarm、setitimer以及abort来完成

kill函数

kill函数用来发送信号给指定的进程。

#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int sig);

该函数的行为与第一个参数pid有关,第二个参数sig表示信号编号。

  • 如果pid是正数,则发送信号sig给进程号为pid的进程
  • 如果pid为0,则发送信号sig给当前进程所属的进程组里的所有进程
  • 如果pid为-1,则把信号sig广播至系统除1号进程(init进程)和自身以外的所有进程
  • 如果pid是比-1还小的负数,则发送信号sig给属于进程组-pid(也就是pid的绝对值) 的所有进程
  • 如果参数sig是0,则kill仍执行正常的错误检查,但不发送信号。可以利用这一点来确定某新城是否有权向另外一个进程发送信号。如果向一个并不存在的进程发送空信号,则kill返回-1,errno被设置为ESRCH

函数执行成功返回0,当有错误发生时返回-1,错误代码存入errno。

注意:只有具有root权限的进程才能向其他任意进程发送信号,非root权限的进程只能向属于同一个组或同一个用户的进程发送信号。

示例程序1

该示例程序实现了自己的kill命令。在shell中kill命令也是用来发送信号的,我们用代码仿照shell的kill命令,但是不支持-l选项(显示信号编号)

//本程序只支持按信号的编号发送信号
#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char **argv){int i,j;int signum=SIGTERM;//默认发送SIGTERMpid_t pid;//首先检查参数,要么是只有一个参数,也就是pid,要么是三个参数,也就是 -s signum pidif(argc!=2&&argc!=4){printf("Usage:./my_kill <-s signum>[PID]\n");exit(0);}for(i=1;i<argc;i++){//如果有-s,找到-s后面的参数,它就是signumif(!strcmp(argv[i],"-s")){signum=atoi(argv[i+1]);break;}}if(argc==2){//如果只有一个参数,它就是pidpid=atoi(argv[1]);}else{for(j=1;j<argc;j++){//i是在-s,所以j=i+2的时候就指向的是pidif(j!=i&&j!=i+1){pid=atoi(argv[j]);break;}}}if(kill(pid,signum)<0){perror("kill");exit(1);}return 0;
}

运行的方式:./my_kill -s 2(这是signum) 2568(这是pid)

这个例子可以配合之前几节写的信号接收的程序使用来测试

raise函数

raise函数是ANSI C而非POSIX标准定义的,用来给调用它的进程发送信号。

#include<signal.h>
int raise(int sig);

示例程序2

这里用raise函数写一个自发自收的信号

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
void process(int signum){printf("recv!\n");
}
int main(int argc,char **argv){signal(SIGINT,process);raise(SIGINT);return 0;
}

这都很简单,就不解释了。

sigqueue函数

这个函数支持信号带有参数,从而可以与函数sigaction配合使用

#include<signal.h>
int sigqueue(pid_t pid,int sig,const union sigval value);

sigqueue的另一个与kill的不同点是它不能给一组进程发送信号

参数value是一个union共用体,定义如下

union sigval{int sival_int;void *sival_ptr;
};

union的特点就是只能是其中一个。也就是说信号携带的要么是一个整型值,要么是一个void型指针。当接收进程的信号处理函数是由sigaction设置的并且设置了SA_SIGINFO标准,接收进程可以从siginfo_t结构的si_value域取得信号发送时携带的参数

成功执行返回0,发生错误返回-1,错误码存到errno里。

程序3

这个函数书上竟然没有给示例,我尝试自己写一个demo来测试一下。

首先是接收方的程序,设置一下sigaction

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
void receive_process(int signum,siginfo_t *info_ptr,void *unused_ptr){printf("recv!\n");printf("data is:%d\n",info_ptr->si_value.sival_int);
}
int main(int argc,char **argv){printf("my pid:%d\n",getpid());struct sigaction act;act.sa_flags=SA_SIGINFO;act.sa_sigaction=receive_process;sigaction(SIGINT,&act,nullptr);while(1);return 0;
}

然后是发送方的程序

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
int main(int argc,char **argv){pid_t pid=atoi(argv[1]);int data=atoi(argv[2]);union sigval value;value.sival_int=data;sigqueue(pid,SIGINT,value);return 0;
}

运行结果如图

完美的发送和接收,证明讲的确实没问题。

我在上一节里写的si_value的类型是sigval_t,我去源码里翻了下, sigval_t和union sigval是一样的,只是重新命名了。 

sigaction不会写的可以看我之前写的文章《Linux C编程实战》笔记:信号的捕捉和处理-CSDN博客

alarm函数

alarm函数可以用来设置定时器,定时器超时将产生SIGALRM信号给调用进程。

#include<unistd.h>
unsigned int alarm(unsigned int seconds);

经过seconds秒后,内核将给调用该函数的进程发送SIGALRM信号,如果seconds为0,则不再发送SIGALRM信号。最新一次调用alarm函数将取消之前一次的设定。

注意:alarm只设定为发送一次信号,如果要多次发送,就要对alarm进行多次调用。

示例程序4

该示例程序模拟网络命令ping的功能。

其实我也不知道ping是干啥的...反正跟着敲吧。

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
void send_ip(){printf("send a icmp echo request packet\n");
}
void recv_ip(){while(1);
}
void handler_sigalarm(int signo){send_ip();alarm(2);
}
int main(int argc,char **argv){signal(SIGALRM,handler_sigalarm);raise(SIGALRM);//触发一个SIGALRM信号给本进程recv_ip();return 0;
}

其实就是一直在发这段话罢了。整个程序也很好懂,就不多讲了。

getitimer/setitimer函数

与alarm函数一样,setitimer函数也是用来设置定时器的,且alarm和setitimer使用的是同一个定时器,因此会相互影响。setitimer要比alarm具有更多的功能。

#include<sys/time.h>
int getitimer(int which,struct itimerval *value);
int setitimer(int which,const struct itimerval *value,struct itimerval *ovalue);

第一个参数which用来指定使用哪一个定时器,根据参数which可单独设定每个定时器,定时器的种类如下:

 参数value用来指定定时器的时间,结构struct itimerval的定义如下:

struct itimerval{struct timeval it_interval;struct timeval it_value;
}
//解释一下setitimer里这个结构体的使用,首先定时器时间是it_value,这个计完后会发一个信号,之后
//it_value会重新变为it_interval,并且之后一直以it_interval为间隔循环计时,计到0也会发送信号
struct timeval{long tv_sec;//秒数long tv_usec;//微秒
}

对于函数getitimer,如果存在由which指定的定时器,则将剩余时间保存在it_value中,该定时器的初始值保存在it_interval中;如果不存在指定类型的定时器,则将value置为0返回。执行成功返回0,当有错误发生时则返回-1,错误代码存入errno中。

示例程序5

#include<stdio.h>
#include<sys/time.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
//信号处理程序
void handler_sigtimer(int signo){switch (signo){case SIGALRM:printf("recv SIGALRM\n");break;case SIGPROF:printf("recv SIGPROF\n");break;default:break;}
}
int main(int argc,char **argv){struct itimerval value;//安装信号处理函数signal(SIGALRM,handler_sigtimer);signal(SIGPROF,handler_sigtimer);//初始化value结构value.it_value.tv_sec=1;    //第一次1秒触发信号value.it_value.tv_usec=0;value.it_interval.tv_sec=5;    //第二次之后都是5秒触发信号value.it_interval.tv_usec=0;//设置定时器setitimer(ITIMER_REAL,&value,nullptr);setitimer(ITIMER_PROF,&value,nullptr);while(1);return 0;
}

程序设置了两个定时器ITIMER_REAL和ITIMER_PROF。系统经过1秒后,将触发一个SIGALRM信号,以后每5秒触发一个SIGALRM信号。按照程序执行时消耗的时间以及内核因本程序消耗的时间来计时。第一次经过一秒后将触发一个SIGPROF信号,以后每5秒触发一个SIGPROF信号。

abort函数

#include<stdlib.h>
void abort(void);

如果进程设置了信号处理函数以捕获SIGABRT信号,且信号处理函数不返回(如使用longjmp),则abort()不能终止进程。abort()终止进程时,所有打开的流(如i/o流、文件流)均会被刷新和关闭。如果进程设置了SIGABRT被阻塞或忽略,abort()将覆盖这种设置。

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

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

相关文章

鸿蒙开发-UI-布局-网格

鸿蒙开发-UI-布局 鸿蒙开发-UI-布局-线性布局 鸿蒙开发-UI-布局-层叠布局 鸿蒙开发-UI-布局-弹性布局 鸿蒙开发-UI-布局-相对布局 鸿蒙开发-UI-布局-格栅布局 鸿蒙开发-UI-布局-列表 文章目录 前言 一、基本概念 二、开发布局 1.排列方式 2.设置行列间距 三、应用特性 1.网格数…

android usb2.0 协议基础(2)

2.4 USB逻辑部件 USB 逻辑部件 设备---》 接口 &#xff08;一个或多个&#xff09;&#xff1a;用于描述特定功能&#xff0c;包含多个端点----》端点&#xff08;一个或多个&#xff09;&#xff1a; 传输的最终对象端点号&#xff0c;传输类型传输方向&#xff0c;最大的数据…

设备通过GB28181注册到EasyCVR,平台看不到设备信息的排查方法汇总

智慧安防平台EasyCVR能在复杂的网络环境中&#xff08;专网、局域网、广域网、VPN、公网等&#xff09;将前端海量的设备进行统一集中接入与视频汇聚管理&#xff0c;平台支持设备通过4G、5G、WIFI、有线等方式进行视频流的接入与传输&#xff0c;支持的接入协议包括&#xff1…

大数据开发之Spark(RDD弹性分布式数据集)

第 1 章&#xff1a;rdd概述 1.1 什么是rdd rdd&#xff08;resilient distributed dataset&#xff09;叫做弹性分布式数据集&#xff0c;是spark中最基本的数据抽象。 代码中是一个抽象类&#xff0c;它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合。 1.1…

Zabbix 微信与钉钉告警配置部署

Zabbix 微信与钉钉告警配置部署 系统环境准备好&#xff1a; Lnmp zabbix-server&#xff1a;172.20.26.167 Mysql主从zabbix-agent&#xff1a;172.20.26.198、172.20.26.24 zabbix的安装部署可以查阅之前的文章&#xff1a;Zabbix 4.0安装部署自动发现及自动注册、自动添…

huggingface学习|云服务器部署Grounded-Segment-Anything:bug总会一个一个一个一个又一个的解决的

文章目录 一、环境部署&#xff08;一&#xff09;模型下载&#xff08;二&#xff09;环境配置&#xff08;三&#xff09;库的安装 二、运行&#xff08;一&#xff09; 运行grounding_dino_demo.py文件&#xff08;二&#xff09;运行grounded_sam_demo.py文件&#xff08;三…

2023年第十六届中国系统架构师大会(SACC2023):核心内容与学习收获(附大会核心PPT下载)

大会以“数字转型 架构演进”为主题&#xff0c;聚焦系统架构在数字化转型中的演进和应用。 与往届相比&#xff0c;本届大会最大的变化是从原来的大会演讲模式变革为专题研讨会模式。专题研讨会主题内容紧扣行业落地实践痛点与难点&#xff0c;多角度聚焦行业的架构演进之路。…

Python requests网络库源码分析(第三篇:通过学习异常模块,了解http协议)

前言 作者在requests包下&#xff0c;定义了exceptions模块&#xff0c;该模块中定义执行http请求过程中常见的错误&#xff0c;熟悉这些错误有助于我们写出健壮的业务程序&#xff0c;同时还能温习http的知识点&#xff0c;本文基于的requests版本为2.27.1 exceptions模块&…

关于网络安全 的 ARP欺骗 实验操作

实验设备&#xff1a; Windows server 2008 kali 1. vmware--上面菜单栏--虚拟机--设置--网络--NAT 模式 确定靶机与攻击机的连通性&#xff08;互相能 ping 通&#xff09; 靶机查看 arp 表&#xff08;arp -a&#xff09; 查看攻击机(kali)物理地址&#xff08;ip addr&…

SpringBoot整合ElasticSearch实现基础的CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述spring-boot-starter-data-elasticsearch项目搭建ES简单的crud操作保存数据修改数据查看数据删除数据 本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest&#xff0c;还有一种就是SpringData-ElasticSearch。根据…

Modern C++ 一个例子学习条件变量

目录 问题程序 施魔法让BUG浮出水面 条件变量注意事项 修改程序 问题程序 今天无意中看到一篇帖子&#xff0c;关于条件变量的&#xff0c;不过仔细看看发现它并达不到原本的目的。 程序如下&#xff0c;读者可以先想想他的本意&#xff0c;以及有没有问题&#xff1a; #…

Zabbix分布式监控系统

实验过程 ps&#xff1a; 阿里云盘Xnode1获取 xnode1 https://www.alipan.com/s/HgLXfoeBWG2 提取码: eb70 1、xnode1克隆两台虚拟机并修改ip zabbix-server192.168.224.3 zabbix-agent192.168.224.4 2、修改主机名 [rootlocalhost ~]# hostnamectl set-hostname zabbix-se…

Vue开始封装全局防抖和节流函数

封装文件 封装文件的实现思路如下&#xff1a; 首先&#xff0c;我们需要定义两个函数&#xff1a;防抖函数和节流函数。这两个函数的目的是为了减少频繁触发某个事件导致的性能问题&#xff1b;防抖函数的实现思路是创建一个计时器变量&#xff0c;用于延迟执行函数。当触发…

Spring Boot 初始(快速搭建 Spring Boot 应用环境)

提示&#xff1a; ① 通过下面的简介可以快速的搭建一个可以运行的 Spring Boot 应用&#xff08;估计也就2分钟吧&#xff09;&#xff0c;可以简单的了解运行的过程。 ② 建议还是有一点 Spring 和 SpringMVC的基础&#xff08;其实搭建一个 Spring Boot 环境不需要也没有关系…

uniapp中打包Andiord app,在真机调试时地图以及定位功能可以正常使用,打包成app后失效问题(高德地图)

踩坑uniapp中打包Andiord app&#xff0c;在真机调试时地图以及定位功能可以正常使用&#xff0c;打包成app后失效问题_uniapp真机调试高德地图正常 打包apk高德地图就不加载-CSDN博客 问题&#xff1a; 目前两个项目&#xff0c;一个项目是从另一个项目里面分割出来的一整套…

AI 赋能绿色制冷,香港岭南大学开发 DEMMFL 模型进行建筑冷负荷预测

近年来&#xff0c;城市化进程加速所带来的碳排放量骤增&#xff0c;已经严重威胁到了全球环境。多个国家均已给出了「碳达峰&#xff0c;碳中和」的明确时间点&#xff0c;一场覆盖全球、全行业的「绿色革命」已经拉开序幕。在一众行业中&#xff0c;建筑是当之无愧的能耗大户…

初识node.js(使用)

文章目录 项目目录介绍和运行流程1.index.html&#x1f447;2.整个项目的核心入口文件其实是main.js3.App.vue 组件化开发 和 根组件普通组件的注册1.局部注册2.全局注册 综合案例 项目目录介绍和运行流程 1.index.html&#x1f447; <!DOCTYPE html> <html lang&quo…

宠物互联网医院系统

在数字时代&#xff0c;宠物医疗迎来了一场革新&#xff0c;动物互联网医院系统以其先进的技术和智能的特性成为宠物护理的领军者。本文将介绍宠物互联网医院系统的一些关键技术和代码示例&#xff0c;揭示这一科技奇迹的实现原理。 1. 远程医疗服务的实现 远程医疗服务是宠…

国标GB28181协议EasyCVR启动失败报错“Local Machine Check Error”的解决方法

国标GB28181安防监控系统EasyCVR平台采用了开放式的网络结构&#xff0c;可支持4G、5G、WiFi、有线等方式进行视频的接入与传输、处理和分发。安防视频监控平台EasyCVR还能支持GIS电子地图模式&#xff0c;基于监控摄像头的经纬度地理位置信息&#xff0c;将场景中的整体安防布…

当pytest遇上poium会擦出什么火花

当pytest遇上poium会擦出什么火花 首先&#xff0c;创建一个test_sample/test_demo.py 文件&#xff0c;写入下面三行代码。 def test_bing(page):page.get("https://www.bing.com")assert page.get_title "必应"不要问题 page 从哪里来&#xff0c;打开…