Linux——信号处理函数与阻塞状态的进程

这篇博客记录一下我在编写一个简单的多进程回声服务器的时候出现的问题。

这个问题就在于忽略了几个有关于信号处理函数的基本常识:

  1. 用通俗的话讲信号注册函数(signal、sigaction)的功能:进程告诉操作系统,当以后收到向信号注册函数传入的信号时,你帮我调用一下信号处理函数。
  2. 当该进程在之后收到指定的信号之后,操作系统就会帮助进程调用指定的信号处理函数。但是,如果该进程处于阻塞状态,那么操作系统会强制唤醒进程!并且不会再陷入之前的阻塞!

下面是我所写的代码中的一个片段(C和C++混编出来的屎,别喷):

 void start()
    {
        // 开始接受客户端请求
        struct sigaction act;
        act.sa_handler = wait_child_proc;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGCHLD,&act,0);

        sockaddr_in client;
        socklen_t len = sizeof(client);
        while(true)
        {

            int sockfd = accept(_listenfd,(sockaddr *)&client,&len);
            if(sockfd == -1)
            {
                printf("accept error!\n");
                continue;
            }
            std::cout << "有新的客户端..." << std::endl;
            pid_t id = fork();
            if(id == 0)
            {
                close(_listenfd);//子进程不负责监听业务
                int recv_len = 0;
                char buffer[1024] = {0};
                while((recv_len = read(sockfd,buffer,sizeof(buffer))) != 0)
                {
                    std::cout << "recv_len = " << recv_len << std::endl;
                    write(sockfd,buffer,recv_len);
                }
                close(sockfd);
                std::cout << "子进程处理完业务!退出!" << getpid() << std::endl;
                exit(0);
            }
            else if(id > 0)
            {
                close(sockfd);// 父进程不处理业务
            }
            else 
            {
               std::cout << "fork error!" << std::endl;
                exit(-1);
            }
        }
    }

这段代码会有两个地方陷入阻塞:一是父进程调用accept时,二是子进程调用read时。而子进程并没有调用信号注册函数,因此子进程与本篇文章研究的问题无关。

这段代码的意思大概是这样:调用start()后,调用sigaction()注册了一个SIGCHLD信号,然后继续往下走直到accept()阻塞。如果accept()返回了一个正确的套接字,那么主进程就创建一个子进程去处理I/O。子进程当中的read()如果返回值为0,就说明连接已经断开了,此时子进程就会退出。同时,在子进程处理I/O的时候,父进程已经在accept()处阻塞了,此时如果子进程处理的I/O连接断开,子进程就会退出,父进程就会收到SIGCHLD信号,然而此时的父进程正处于阻塞状态,所以操作系统会强制唤醒父进程以便调用信号处理函数,而父进程的accept()没有收到任何可用连接并且又从accept()处唤醒,因此accept()的返回值为-1,所以会打印一个"accept error!"。

虽然这段代码并不会给服务器带来任何功能上的差错,但是一个连接断开就打印一次"accept error!"确实是比较奇怪的。因此写下该篇文章以做记录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小龙向钱进

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值