UNIX环境高级编程之-----信号signal

参考书籍:unxi环境高级编程


信号函数:

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

其原型为:

void (*signal(int signum,void (*handler)(int))) (int);

我们一般都是用第一个,也就是通过typedef改写过的。

注意:signal函数我一般认为其是向内核注册当前进程收到信号的处理的方式。
signal(SIGINT,handler);

参数说明:

signum  :  指定信号
handler  :  SIG_IGN忽略该信号,SIG_DFL采用系统默认方式处理信号,自定义的信号处理函数指针。

理解实际的例子是学习的最好方式:
例子一:
通过异步方式,给子进程收尸

注意:子进程在终止时会给父进程发SIGCHLD,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需要专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。


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


void child_exit_handler(int signum)
{
    if(signum == SIGCHLD)
    {
        printf("Child exit.\n");
        wait(NULL);
    }
}

int main()
{
    int pid;
    int i = 0;

    //想内核注册,处理 SIGCHLD信号的方式
    signal(SIGCHLD,child_exit_handler);

    if((pid = fork()) < 0)
    {
        perror("Fail to fork");
        exit(EXIT_FAILURE);

    }else if(pid == 0){
        
        for(i = 0;i < 5;i ++)
        {
            printf("child loop.\n");
            sleep(1);
        }
    
    }else{
        
        for(i = 0;i < 5;i ++)
        {
            printf("Father loop.\n");
            sleep(2);
        }

    }

    exit(EXIT_SUCCESS);
}

运行结果如下:
[uglychen@chenxun test]$gcc test.c 
[uglychen@chenxun test]$ ls
a.out  test.c
[uglychen@chenxun test]$ ./a.out 
child loop.
Father loop.
child loop.
Father loop.
child loop.
child loop.
Father loop.
child loop.
Child exit.
Father loop.
Father loop.

[uglychen@chenxun test]$ 

例二、综合案例

使用FIFO实现clientA与clientB之间聊天
A.输入quit后,两个进程退出
B.如果在20秒内,没有等到另一端发来的消息,则认为对方已不在,此时终止。

clientA:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define MAX 100

void signal_handler(int signum)
{
    static int flag = 0;

    switch(signum)
    {
        case SIGALRM:
            if(flag == 0)
            {
                printf("The people is leaving,the system is closed in 10 seconds \
                        and you can input 'ctrl + c' cancel.\n");
                alarm(10);
            }else{
                
                kill(getppid(),SIGKILL);
                usleep(500);
                exit(EXIT_SUCCESS);
            }

            flag = 1;            
            break;

        case SIGINT:
            printf("The alarm is cancel.\n");
            alarm(0);
            break;
    }

}

int child_recv_fifo(char *fifo_name)
{
    int n,fd;
    char buf[MAX];

    if((fd = open(fifo_name,O_RDONLY)) < 0)
    {
        fprintf(stderr,"fail to open %s : %s.\n",fifo_name,strerror(errno));
        return -1;
    }

    signal(SIGALRM,signal_handler);
    signal(SIGINT,signal_handler);
    alarm(15);//璁剧疆瀹氭椂鍣?    
    while(1)
    {
        n = read(fd,buf,sizeof(buf));
        buf[n] = '\0';

        printf("Read %d bytes : %s.\n",n,buf);

        if(strncmp(buf,"quit",4) == 0 || n == 0)
        {
            kill(getppid(),SIGKILL);
            usleep(500);
            exit(EXIT_SUCCESS);
        }

        alarm(15);
    }

    return 0;
}

int father_send_fifo(char *fifo_name,int pid)
{
    int n,fd;
    char buf[MAX];

    if((fd = open(fifo_name,O_WRONLY)) < 0)
    {
        fprintf(stderr,"Fail to open %s : %s.\n",fifo_name,strerror(errno));
        return -1;
    }

    signal(SIGINT,SIG_IGN);

    while(1)
    {
        getchar();
        printf(">");

        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';

        write(fd,buf,strlen(buf));

        if(strncmp(buf,"quit",4) == 0)
        {
            kill(pid,SIGKILL);
            usleep(500);
            exit(EXIT_SUCCESS);
        }
    }

    return 0;
}

int main(int argc,char *argv[])
{
    int pid;

    if(argc < 3)
    {
        fprintf(stderr,"usage %s argv[1].\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
    {
        perror("Fail to mkfifo");
        exit(EXIT_FAILURE);
    }

    if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
    {
        perror("Fail to mkfifo");
        exit(EXIT_FAILURE);
    }
    
    if((pid = fork()) < 0)
    {
    
        perror("Fail to fork");
        exit(EXIT_FAILURE);
    
    }else if(pid == 0){
        
        child_recv_fifo(argv[2]);
    
    }else{

        father_send_fifo(argv[1],pid);
    }

    exit(EXIT_SUCCESS);
}

client B
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define MAX 100

void signal_handler(int signum)
{
    static int flag = 0;

    switch(signum)
    {
        case SIGALRM:
            if(flag == 0)
            {
                printf("The people is leaving,the system is closed in 10 seconds \
                        and you can input 'ctrl + c' cancel.\n");
                alarm(10);
            }else{
                
                kill(getppid(),SIGKILL);
                usleep(500);
                exit(EXIT_SUCCESS);
            }

            flag = 1;            
            break;

        case SIGINT:
            printf("The alarm is cancel.\n");
            alarm(0);
            break;
    }

}

int child_recv_fifo(char *fifo_name)
{
    int n,fd;
    char buf[MAX];

    if((fd = open(fifo_name,O_RDONLY)) < 0)
    {
        fprintf(stderr,"fail to open %s : %s.\n",fifo_name,strerror(errno));
        return -1;
    }

    signal(SIGALRM,signal_handler);
    signal(SIGINT,signal_handler);
    alarm(15);//璁剧疆瀹氭椂鍣?    
    while(1)
    {
        n = read(fd,buf,sizeof(buf));
        buf[n] = '\0';

        printf("Read %d bytes : %s.\n",n,buf);

        if(strncmp(buf,"quit",4) == 0 || n == 0)
        {
            kill(getppid(),SIGKILL);
            usleep(500);
            exit(EXIT_SUCCESS);
        }

        alarm(15);
    }

    return 0;
}

int father_send_fifo(char *fifo_name,int pid)
{
    int n,fd;
    char buf[MAX];

    if((fd = open(fifo_name,O_WRONLY)) < 0)
    {
        fprintf(stderr,"Fail to open %s : %s.\n",fifo_name,strerror(errno));
        return -1;
    }

    signal(SIGINT,SIG_IGN);

    while(1)
    {
        getchar();
        printf(">");

        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';

        write(fd,buf,strlen(buf));

        if(strncmp(buf,"quit",4) == 0)
        {
            kill(pid,SIGKILL);
            usleep(500);
            exit(EXIT_SUCCESS);
        }
    }

    return 0;
}

int main(int argc,char *argv[])
{
    int pid;

    if(argc < 3)
    {
        fprintf(stderr,"usage %s argv[1].\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
    {
        perror("Fail to mkfifo");
        exit(EXIT_FAILURE);
    }

    if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
    {
        perror("Fail to mkfifo");
        exit(EXIT_FAILURE);
    }
    
    if((pid = fork()) < 0)
    {
    
        perror("Fail to fork");
        exit(EXIT_FAILURE);
    
    }else if(pid == 0){
        
        child_recv_fifo(argv[1]);
    
    }else{

        father_send_fifo(argv[2],pid);
    }

    exit(EXIT_SUCCESS);
}











  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值