Linux进程间通信之信号

Linux进程间通信之信号

一:信号
信号通信,其实就是内核向用户空间进程发送信号,只有内核才能发信号,用户空间进程不能发送信号。信号其实已经在内核存在了。
内核可以发送多少种信号呢?
kill -l
64种
命令:kill -9 pid
注:1.告诉内核发送什么信号;
2.告诉内核发给谁。
信号通信的框架
信号的发送(发送信号进程):kill raise alarm
信号的接收(接收信号进程) : pause() sleep while(1)//这3中方式可以
信号的处理(接收信号进程) : signal

1.信号的发送(发送信号进程)
kill :
头文件 #include <signal.h>
#include <sys/types.h>
函数原型 int kill(pid_t pid, int sig);
函数传入值
pid: 正数:要接收信号的进程的进程号
0:信号被发送到所有和pid进程在同一个进程组的进程
-1:信号发给所有的进程表中的进程(除了进程号最大的进程外)
sig:信号
函数返回值
成功:0
出错:-1

raise: 发信号给自己 == kill(getpid(), sig)
头文件 #include <signal.h>
#include <sys/types.h>
函数原型 int raise(int sig);
函数传入值 sig:信号
函数返回值
成功:0
出错:-1

#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{ 
  //没有加\n就会出现没有显示
  //数据写到了行缓存中去了的
  printf("raise before");
  raise(9);// _exit()相当于raise,不刷新缓存
  		   // exit()会把上面在行缓存中的数据发给内核,然后输出
  printf("raise after\n");
  return 0;
}

在这里插入图片描述

#include "stdio.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
  pid_t pid;
  pid=fork();
  if(pid > 0 )
  {
    sleep(8);
    //WNOHANG以非阻塞调用,没有子进程状态发生改变
    //waitpid不阻塞立即返回此时的返回值为0
	if(waitpid(pid,NULL,WNOHANG) == 0)
	{
	  kill(pid,9);//杀死子进程
	}
	//回收僵尸态子进程,如果没有僵尸态子进程
	//则阻塞,null是指忽略子进程退出的状态
	wait(NULL);
	while(1);
  }
  if(pid ==  0)
  {
   printf("raise function before\n");
   raise(SIGTSTP);
   printf("raise funtion after\n");
   exit(0);
  }
  return 0;
}

在这里插入图片描述
alarm : 发送闹钟信号的函数:
alarm 与 raise 函数的比较:
相同点:让内核发送信号给当前进程
不同点:
1.alarm 只会发送SIGALARM信号
2.alarm 会让内核定时一段时间之后发送信号, raise会让内核立刻发信号

所需头文件 #include <unistd.h>
函数原型 unsigned int alarm(unsigned int seconds)
函数传入值 seconds:指定秒数
函数返回值 成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则
返回上一个闹钟时间的剩余时间,否则返回0。
出错:-1

在这里插入图片描述
2. 信号的接收(接收信号进程)
接收信号的进程,要有什么条件:要想使接收的进程能收到信号,这个进程不能结束 :
sleep
**pause:**进程状态为S(运行到这里会给当前进程发睡眠状态并一直处于睡眠状态)
while(1)
所需头文件 #include <unistd.h>
函数原型 int pause(void);
函数返回值 成功:0,出错:-1

#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>

int main()
{ 
  int i;
  i=0;
  printf("pause before\n");
  pause();
  printf("pause after\n");
  while(i< 20)
  {
	i++;
	sleep(1);
	printf("process things,i=%d\n",i);
  }
  return 0;
}

在这里插入图片描述
3.信号的处理(接收信号进程)
收到信号的进程,应该怎样处理? 处理的方式:
(1)进程的默认处理方式(内核为用户进程设置的默认处理方式)
A:忽略
B:终止进程
C: 暂停
(2)自己的处理方式:
自己处理信号的方法告诉内核,这样你的进程收到了这个信号就会采用你自己的的处理方式

所需头文件 #include <signal.h>
函数原型 void (*signal(int signum, void (*handler)(int)))(int);
函数传入值 signum:指定信号(告诉内核处理哪一个信号)
handler: 告诉
内核用什么方法去处理
SIG_IGN:忽略该信号。
SIG_DFL:采用系统默认方式处理信号。
自定义的信号处理函数指针
函数返回值
成功:设置之前的信号处理方式
出错:-1

signal 函数有二个参数,第一个参数是一个整形变量(信号值),第二个参数是一个函数指针,是我们自己写的处理函数;
void (*handler)(int)是一个函数指针变量,函数的形式:含有一个整型参数,无返回值的函数,
这个函数的返回值是一个函数指针。

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

void myfun(int signum)
{
  int i;
  i=0;
  while(i < 5)
  {
	printf("process signal signum=%d\n",signum);
	sleep(1);
	i++;
  }
  //信号处理函数处理完之后就回到主函数中继续运行
  return; // return main

}
int main()
{ 
  int i;
  i=0;
  //9s后alarm发的14号信号后,执行信号处理函数
  signal(14,myfun);
  printf("alarm before\n");
  //alarm会给内核发SIGALRM(14号信号)
  alarm(9);
  printf("alarm after\n");
  while(i< 10)
  {
	i++;
	sleep(1);
	printf("process things,i=%d\n",i);
  }
  return 0;
}

在这里插入图片描述

#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>

void myfun(int signum)
{
  int i;
  i=0;
  while(i < 10)
  {
	printf("process signal signum=%d\n",signum);
	sleep(1);
	i++;
  }
  return; // return main
}
int main()
{ 
  int i;
  i=0;
  signal(14,myfun);
  printf("alarm before\n");
  alarm(9);
  printf("alarm after\n");
  signal(14,SIG_IGN);
  signal(14,SIG_DFL); //系统会以这条为最新的信号函数去执行,以默认的方式去处理9号信号的
  while(i< 20)
  {
	i++;
	sleep(1);
	printf("process things,i=%d\n",i);
  }
  return 0;
}

在这里插入图片描述
利用信号实现进程间的通信

#include "stdio.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void myfun(int signum)
{
  int i;
  i=0;
  while(i <2)
  {
	printf("receive signum=%d,i=%d\n",signum,i);
	sleep(1);
	i++;
  }
  return;
}
void myfun1(int signum)
{
  printf("receive signum=%d\n",signum);
  wait(NULL);
  return ;
}

int main()
{
  pid_t pid;
  pid=fork();
  if(pid > 0 )
  {
	int i;
	i=0;
	signal(10,myfun);
	signal(17,myfun1);
	while(1)
	{
     printf("parent process things,i=%d\n",i);
	 sleep(1);
	 i++;
	}
  }
  if(pid ==  0)
  {
	sleep(5);
	kill(getppid(),10);
	sleep(5);
	exit(0);//kill(getppid(),17)
  }
  return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、imp2源码 整个源码包含三个文件:imp2_k.c, imp2_u.c和imp2.h. 其中imp2_k.c为内核模块的源代码,imp2_u.c为应用程序,即测试代码,imp2.h为两个源文件都需要引用的头文件。其整体的功能是:注册一种新的netlink协议,并注册一个新的NF hook函数。当有ping包发往当前主机或者经过当前主机转发时,内核用户发送ping包的源IP和目的IP。各个文件的简单分析见下文。 1. imp2.h 该文件主要是定义了一种新的Netlink协议类型NL_IMP2(31)。新的协议类型的选值不能和当前内核中已经定义的netlink协议类型重复。定义了基于该协议类型的消息类型,内核根据接收到消息的不同类型,进行不同的处理:IMP2_U_PID和IMP2_CLOSE分别为请求和关闭。IMP2_K_MSG代表内核空间发送的消息。 该头文件的源码如下: 2. imp2_k.c 该程序为内核模块程序。其完成的功能如下: (1)创建一种新的Netlink协议NL_IMP2,并注册该协议的回调函数kernel_receive。但用户空间通过建立且协议类型为NL_IMP2的socket套接字并调用sendto,sendmsg函数发送数据时,传送到内核空间的数据由kernel_receive进行处理。该函数主要是记录用户进程的ID,用于随后发送数据的时候指定目的。 (2)在Netfilter的hook点NF_IP_PRE_ROUTING注册hook函数get_icmp,对经过该hook点的ping包进行处理。get_icmp首先判断是否是ping包,如果不是,直接Accept。如果是,则记录该包的源IP和目的IP,然后调用send_to_user,将记录的信息发送给kernel_recieve函数中记录的用户进程ID。 该文件的源码如下: 3. imp2_u.c 该程序为用户空间的测试程序。该程序包括以下功能: (1)生成NL_IMP2协议的socket.然后通过调用sendto发送IMP2_U_PID类型的请求信息给内核。然后等待接受内核发回的信息。记住:仅当有ping包经过内核的NF时,内核才会向用户进程发送信息。 (2)当用户进程通过Ctrl+C来结束该程序时,调用信号处理函数sig_int,向内核发送IMP2_CLOSE的消息,结束socket。 该文件的源码如下: 二、编译和测试 1. 整个源文件编译的Makefile如下: all: gcc -O2 -DMODULE -D__KERNEL__ -W -Wstrict-prototypes -Wmissing-prototypes -isystem /lib/modules/`uname -r`/build/include -c -o imp2_k.o imp2_k.c gcc imp2_u.c -o imp2_u install: insmod imp2_k.o uninstall: rmmod imp2_k clean: rm -f imp2_k.o imp2_u 2. 加载内核模块,并执行测试程序。 #make install #./imp2_u 当没有ping包时,终端一直处于等待输出状态。通过另一台主机(192.168.1.100)向当前主机(192.168.1.101)发送ping包,则终端已经有输出: #./imp2_u [root@localhost imp2]# ./imp2_u src: 192.168.1.100, dest: 192.168.1.101 src: 192.168.1.100, dest: 192.168.1.101 src: 192.168.1.100, dest: 192.168.1.101 src: 192.168.1.100, dest: 192.168.1.101
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值