• 进程池前期


    1. 信号处理问题

    对于相同信号,按信号的先后顺序依次处理。可能会产生的问题是,正在处理sig1信号时,又来了2个或更多的sig1信号,此sig1时只会在处理完原来的sig1信号后,再处理1个sig1信号。因此对于相同信号,会产生信号掉包的问题。 一个儿子退了之后,程序在处理handler(),如果此时又退了两个儿子,那么必然有一个儿子的资源回收不到,称为僵尸进程。

    对于不同信号,优先处理后者,处理完后者在回头处理上一个。例如正在处理sig1时,来了sig2,则会先处理sig2,等处理完sig2后,回过头继续处理sig1。

    2. 解决方案

    在注册的信号处理函数中,使用循环,并在循环中用waitpid来回收子进程资源。只要进入信号处理函数,那么该信号处理函数就可以把所有fork出的儿子的资源都回收掉。注意:waitpid要设置成非阻塞模式,不然当进入循环后,如果没有子进程退出时,会阻塞在信号处理函数中。

    3. wait与waitpid

    wait一定是阻塞模式。因此在信号处理函数中,用while1{wait(NULL)}有问题,如果进入信号处理函数后,只要有儿子不退,就会一直阻塞在这里。

    waitpid可以是阻塞模式,也可以是非阻塞模式。

    4. select与accept

    两者在收到信号时,均会返回-1。

    对于系统默认不处理的信号,程序收不到,两者当然也不会返回-1。换句话说,SIGCHLD是系统默认不处理的信号,如果不对其注册信号处理函数,当子进程退出时,select与accept也是不会返回-1的。

    //server.c

    #include "my_socket.h"
    #include <sys/wait.h>
    #include <signal.h>
    #include <errno.h>
    #define MY_IP "192.168.1.100"
    #define MY_PORT 8888
    #define SIZE 192
    #define MSG_SIZE (SIZE - 4)
    extern int errno ;
    typedef struct tag_mag
    {
        int  msg_len;//记录msg_buf的真实大小
        char msg_buf[MSG_SIZE];//msg_buf所占空间为188byte
    }MSG, *pMSG;
    
    void my_handle(int num)
    {
        /*waitpid参数:
         * -1表示回收每一个儿子
         * NULL表示不关心子进程的exit的返回值
         * WNOHANG:wait no hang 非阻塞模式
         *waitpid返回值:
         * -1表示没有创建任何儿子
         *  0表示没有儿子退出
         *大于0表示有儿子退出
         * */
        while(waitpid(-1, NULL, WNOHANG ) > 0) ;
    }
    
    int main(int argc, char* argv[])
    {
        int fd_listen , fd_client ;
        signal(SIGCHLD, my_handle);
        my_socket(&fd_listen, MY_TCP, MY_IP ,MY_PORT);
        my_listen(fd_listen, 10);
    
        while( fd_client = accept(fd_listen, NULL, NULL))
        {
            /* 只要不是程序默认忽略的信号,accept都能收到,并返回-1 */
            if(fd_client == -1)
            {
                if(errno == EINTR)
                {
                    continue ;
                }else 
                {
                    break ; //break退出后,父亲就退了。下来儿子会由init接管。
                }
            }else 
            {
                if(fork() == 0) //fork儿子用于与客户端通信
                {
                    MSG recv_msg ;
                    int recvn;
                        while(1 )
                        {
                            memset(&recv_msg, 0, sizeof(MSG));
                            /*在my_socket.c中,my_recv接收的长度 与 my_send 发送的长度必须是精确值 
                             * my_recv中填的长度小于等于实际要收的,是可以的,大于的话就永远退不出循环了*/
                            my_recv(&recvn, fd_client, &recv_msg, 4);
                            if(recvn == 0) //当对面客户端退出(关闭socket),系统调用recv的返回值为0
                            {
                                break ;
                            }else
                            {
                                my_recv(NULL,fd_client, &recv_msg.msg_buf, recv_msg.msg_len);
                                my_send(NULL, fd_client, &recv_msg, 4 + recv_msg.msg_len);
    
                            }
                        }
                    close(fd_client);
                    exit(0);    
                }
                close(fd_client);
            }
        }
        return 0 ;
    }


    //client.c
    #include "my_socket.h"
    #define MY_IP "192.168.1.100"
    #define MY_PORT 6666
    #define SER_IP "192.168.1.100"
    #define SER_PORT 8888
    #define SIZE 192
    #define MSG_SIZE (SIZE - 4)
    typedef struct tag_mag 
    {
        int msg_len ;
        char msg_buf[MSG_SIZE];//188
    }MSG, *pMSG;
    int main(int argc, char* argv[])
    {
        int sfd ;
        my_socket(&sfd, MY_TCP, MY_IP, MY_PORT);
        my_connect(sfd, SER_IP, SER_PORT);
        MSG my_msg ;
        while(memset(&my_msg, 0, sizeof(MSG)), fgets(my_msg.msg_buf, MSG_SIZE, stdin)!= NULL)
        {
            my_msg.msg_len = strlen(my_msg.msg_buf);
            my_send(NULL, sfd, &my_msg, 4 + my_msg.msg_len );
            memset(&my_msg, 0, sizeof(MSG));
            my_recv(NULL, sfd, &my_msg, 4);
            my_recv(NULL, sfd, &my_msg.msg_buf, my_msg.msg_len);
            printf("recv from server : %s 
    ", my_msg.msg_buf);
        
        }
        close(sfd);
    
    }
  • 相关阅读:
    发送带有正文以及附件的邮件
    软件测试笔记
    java开发 中台
    postman测试带有json数据格式的字段
    maven详解之仓库
    Maven与nexus关系
    占位
    Vue项目碰到"‘webpack-dev-server’不是内部或外部命令,也不是可运行的程序或批处理文件"报错
    了解facade设计模式
    postman使用
  • 原文地址:https://www.cnblogs.com/hxjbc/p/3966515.html
Copyright © 2020-2023  润新知