本文主要探讨unix/linux间的一种通信方式———信号。
信号简介
信号是一种特殊的IPC(进程间通讯),它是系统里面已经设计好的,我们只能去使用它,且是一种异步通信方式。
信号相关函数
捕捉信号
typedef void (*sighandler_t)(int signai_num);
参数:
signai_num:数字信号
信号转为指令
sighandler_t signal(int signum, sighandler_t handler);
参数:
signum:信号指令
handler:捕获信号函数
常见几种信号:
2 SIGINT 键盘产生的中断(Ctrl-C)
9 SIGKILL 强制进程
10 SIGUSR1 用户信号,进程可自定义用途
12 SIGUSR2 用户信号,进程可自定义用途
信号发送
int sigqueue(pid_t pid, int sig, const union sigval value);
参数:
pid:进程号
sig:数字信号
value:信号传递的参数,大小4字节
union sigval {
int sival_int; 数值
void *sival_ptr; 字符串
};
返回值:
成功执行返回0,失败返回-1
信号接收
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
参数:
signum:数字信号
act:新的信号处理方式
oldact:老的信号的处理方式
struct sigaction act {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
struct sigaction *oldact 对struct sigaction *act备份,不需要备份为NULL
sigaction(SIGINT, &oldact, NULL); 恢复成原始
信号处理函数可以用void (*sa_handler)(int)或void (*sa_sigaction)(int, siginfo_t *,
void*),取决于sa_flags的SA_SIGINFO位,设置了采用void (*sa_sigaction)(int,
siginfo_t *, void *),可向处理函数发附加信息;默认采用void (*sa_handler)(int),此
时只能向处理函数发送信号的数值。
sa_handler:此参数和signal()的参数handler相同
sa_mask:用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置。
sa_flags:
SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置
为缺省值SIG_DFL
SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动
该系统调用
SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该
给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函
数运行时,内核将不会阻塞该信号
void signal_handler(int signal_num,siginfo_t *info,void *context)
siginfo_t {
int si_signo;信号号
int si_errno;错误值
int si_code;信号代码
int si_trapno;产生的Trap号来自硬件信号(大多数架构上未使用)
pid_t si_pid;发送进程号
uid_t si_uid;发送进程的真实用户ID
int si_status;退出值或信号
clock_t si_utime;用户使用时间
clock_t si_stime;系统消耗时间
sigval_t si_value;信号值
对应发送sigqueue中的信号内容
union sigval {
int sival_int;
void *sival_ptr;
};
int si_int; POSIX.1b信号
void * si_ptr; POSIX.1b信号
int si_overrun;定时器超时次数;POSIX.1b定时器
int si_timerid;定时器ID;POSIX.1b定时器
void * si_addr;导致故障的内存位置
long si_band;band event
int si_fd;文件描述符
short si_addr_lsb;地址的最低有效位
};
demo1:
编写信号接收程序,接收SIGINT信号不能停止的程序
程序示例:
#include <signal.h>
#include <stdio.h>
void sighandler_t(int sign_num)
{
printf("input singnal num :%d\n",sign_num);
printf("not quit\n");
}
void result()
{
signal(SIGINT,sighandler_t);
while(1);
}
int main()
{
result();
return 0;
}
结果示例:
demo2:
编写程序,将输入2(SIGINT),变为9(SIGKILL)信号。
程序示例:
#include <stdio.h>
#include <signal.h>
void sighandler_t(int sign_num)
{
}
void result()
{
printf("input everyone,real input singnal num : 9\n");
signal(SIGKILL,sighandler_t);
while(1);
}
int main()
{
result();
return 0;
}
结果示例:
demo3:
1.编写信号发送程序,发送一个int值
2.编写信号接收程序,接收int值
发送程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
void result(char pid_input[],char sig_num_input[],char num_input[])
{
int pid;
int sig_num;
int num;
sig_num = atoi(sig_num_input);
num = atoi(num_input);
pid = atoi(pid_input);
union sigval value;
value.sival_int = num;
sigqueue(pid,sig_num,value);
}
int main(int argc,char **argv)
{
if(argc != 4)
{
printf("param is error\n");
perror("why");
exit(-1);
}
result(argv[1],argv[2],argv[3]);
return 0;
}
接收程序:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void signal_handler(int signal_num,siginfo_t *info,void *context)
{
printf("signal num is %d\n",signal_num);
printf("get data : %d\n",info->si_int);
printf("get data : %d\n",info->si_value.sival_int);
}
void result()
{
printf("pid : %d\n",getpid());
struct sigaction act;
act.sa_sigaction = signal_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGKILL,&act,NULL);
while(1);
}
int main()
{
result();
return 0;
}
结果示例:
demo4:
1.编写信号发送程序,发送hello word
2.编写信号接收程序,接收hello word
发送程序:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void result(char pid_input[],char sig_num_input[])
{
char *context = "hello word";
int pid;
int sig_num;
key_t key;
int shmid;
char *shmaddr = NULL;
pid = atoi(pid_input);
sig_num = atoi(sig_num_input);
key = ftok(".",127);
if(key == -1)
{
printf("create key fail\n");
perror("why");
exit(-1);
}
shmid = shmget(key,20,IPC_CREAT|0777);
union sigval value;
value.sival_ptr = (void *)shmat(shmid,0,0);
strcpy((char *)value.sival_ptr,context);
sigqueue(pid,sig_num,value);
sleep(10);
shmdt(shmaddr);
}
int main(int argc,char **argv)
{
if(argc != 3)
{
printf("param is error\n");
perror("why");
exit(-1);
}
result(argv[1],argv[2]);
return 0;
}
接收程序:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void signal_handler(int signal_num,siginfo_t *info,void *context)
{
key_t key;
int shmid;
key = ftok(".",127);
if(key == -1)
{
printf("creat key fail\n");
perror("why");
exit(-1);
}
shmid = shmget(key,20,IPC_CREAT|0777);
info->si_value.sival_ptr = (void *)shmat(shmid,0,0);
printf("signal num : %d\n",signal_num);
if(context != NULL)
{
printf("get context : %s\n",info->si_value.sival_ptr);
}
shmctl(shmid,IPC_RMID,NULL);
shmdt(info->si_value.sival_ptr);
}
void result()
{
struct sigaction act;
act.sa_sigaction = signal_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGKILL,&act,NULL);
while(1);
}
int main()
{
printf("pid : %d\n",getpid());
result();
return 0;
}
结果示例: