current position:Home>Advanced IO for Linux learning: the choice of I/O multiplexing

Advanced IO for Linux learning: the choice of I/O multiplexing

2022-08-06 19:12:06Cola_Forever

select

select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;
程序会停在select这里等待,直到被监视的文件描述符有一个或多个发生了状态改变

举例说明:Suppose that we bought a fishing100个鱼竿,Then put it all away and start fishing,But we don't want to wait,So we let aselectwho are monitoring for us which rods have fish bites,然后让selecttell us to come back and catch the fish.
To put it bluntly, we are batchingIOdon't want to wait,让selecthelp us wait,等可以IOlet us know.

select函数原型

在这里插入图片描述

以fd_set *readfdsto explain the middle3个参数含义

在这里插入图片描述

以只读为例,通过代码理解select机制(Need to be used with the third put array,reflected in the code)

Code content for me asserver端进行listen,利用selectfunction will i care aboutlistensocket for supervision,
when a new link comes up,put in maintenancesock的fd_array数组中
仔细看注释

#include <iostream>
#include <string>
#include <sys/select.h>
#include "Sock.hpp"

#define NUM (sizeof(fd_set) * 8)

int fd_array[NUM]; //内容>=0,合法的fd,如果是-1,该位置没有fd

static void Usage(std::string proc)
{
    
    std::cout << "Usage: " << proc << " port" << std::endl;
}

// ./select_server 8080
int main(int argc, char *argv[])
{
    
    if (argc != 2)
    {
    
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = (uint16_t)atoi(argv[1]);
    int listen_sock = Sock::Socket();
    Sock::Bind(listen_sock, port);
    Sock::Listen(listen_sock);
    for (int i = 0; i < NUM; i++)
    {
    
        fd_array[i] = -1;
    }

    // accept: 不应该,acceptThe essence is called throughlisten_sock获取新链接
    // 前提是listen_sockWith the new link,acceptHow do I know there is a new link???
    // 不知道!!!accept阻塞式等待
    // From the point of view of multiplexing,我们认为,link coming,对于listen_sock,read event ready!!!
    // 对于所有的服务器,最开始的时候,只有listen_sock

    //事件循环
    fd_set rfds;
    //因为listen_sock是固定存在的,Therefore, the newsock都是从4开始,放入fd_arry的位置是从1开始
    fd_array[0] = listen_sock;//此时的listen_sock等于3
    for (;;)
    {
    
        FD_ZERO(&rfds);//First set the bitmap to0
        int max_fd = fd_array[0];
        for (int i = 0; i < NUM; i++)
        {
    
            if (fd_array[i] == -1)
                continue;
            //The following are all legalfd
            FD_SET(fd_array[i], &rfds); //All that care about read eventsfd,添加到rfds中
            if (max_fd < fd_array[i])
            {
    
                max_fd = fd_array[i]; //更新最大fd
            }
        }

        struct timeval timeout = {
    0, 0}; // 5s
        // All on our serverfd(包括listen_sock),都要交给select进行检测!!
        // recv,read,write,send,accept : Only responsible for your core work:true read and write(listen_sock:accept)
        int n = select(max_fd + 1, &rfds, nullptr, nullptr, nullptr); //暂时阻塞
        switch (n)
        {
    
        case -1:
            std::cerr << "select error" << std::endl;
            break;
        case 0:
            std::cout << "select timeout" << std::endl;
            break;
        default:
            std::cout << "有fdThe corresponding event is ready!" << std::endl;
            for (int i = 0; i < NUM; i++)//Need to loop through to find readyfd
            {
    
                if (fd_array[i] == -1)
                    continue;
                //下面的fd都是合法的fd,合法的fdnot necessarily readyfd
                if (FD_ISSET(fd_array[i], &rfds))//找到fd为1的
                {
    
                    std::cout << "sock: " << fd_array[i] << " read event above,可以读取了" << std::endl;
                    // Must be read event ready!!!
                    // 就绪的fd就在fd_array[i]保存!
                    // read, recv时,must not be blocked!
                    // 读事件就绪,it must be possiblerecv,read吗??不一定!!
                    if (fd_array[i] == listen_sock)//需要先判断fdDid we deposit in the first place?listen套接字
                    {
    
                        std::cout << "listen_sock: " << listen_sock << " With a new link coming" << std::endl;
                        // accept
                        int sock = Sock::Accept(listen_sock);//This is the real new connection
                        if (sock >= 0)
                        {
    
                            std::cout << "listen_sock: " << listen_sock << " Get new link success" << std::endl;
                            // 获取成功
                            // recv,read了呢?绝对不能!
                            // new link coming,doesn't mean data is coming!!When will the data arrive??不知道
                            // 可是,Who can best know thosefd,above can be read?select!
                            // 无法直接将fd设置进select,但是,好在我们有fd_array[]!

                            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                            // 需要为新的fd在fd_arrayfind a new place to store him,go through the next cycleif (fd_array[i] == listen_sock)对应的else语句来进行read操作!!!
                            // It's important not to start the first timereadbut the next cycle!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                            int pos = 1;
                            for (; pos < NUM; pos++)
                            {
    
                                if (fd_array[pos] == -1)
                                    break;
                            }
                            // 1. Found a location that is not in use
                            if (pos < NUM)
                            {
    
                                std::cout << "新链接: " << sock << " has been added to the array[" << pos << "]的位置" << std::endl;
                                fd_array[pos] = sock;
                            }
                            else
                            {
    
                                // 2. found allfd_array[],No location was found that was not used
                                // Indicates that the server is fully loaded,Unable to handle new requests
                                std::cout << "The server is full,close new link" << std::endl;
                                close(sock);
                            }
                        }
                    }
                    else//Here is the normal readingsock的地方,Must be the first time,放到fd_arrayThe second loop in the array can only operate on it
                    {
    
                        // 普通的sock,read event ready!
                        // can be read,recv,read
                        // 可是,Will it be possible to read this time??读完,There must be no so-called packet sticking problem??
                        // 但是,We can't solve it today!We don't have a scene today!仅仅用来测试
                        std::cout << "sock: " << fd_array[i] << " Normal read above" << std::endl;
                        char recv_buffer[1024] = {
    0};
                        ssize_t s = recv(fd_array[i], recv_buffer, sizeof(recv_buffer) - 1, 0);
                        if (s > 0)
                        {
    
                            recv_buffer[s] = '\0';
                            std::cout << "client[ " << fd_array[i] << "]# " << recv_buffer << std::endl;
                        }
                        else if (s == 0)//Closing the connection requiresfd_arrayThe original location is cleared for future use
                        {
    
                            std::cout << "sock: " << fd_array[i] << "关闭了, client退出啦!" << std::endl;
                            //The peer closed the link
                            close(fd_array[i]);
                            std::cout << "already subscripted in the arrayfd_array[" << i << "]"
                                      << "中,去掉了sock: " << fd_array[i] << std::endl;
                            fd_array[i] = -1;
                        }
                        else//同上elseif注释
                        {
    
                            //读取失败
                            close(fd_array[i]);
                            std::cout << "already subscripted in the arrayfd_array[" << i << "]"
                                      << "中,去掉了sock: " << fd_array[i] << std::endl;
                            fd_array[i] = -1;
                        }
                    }
                }
            }
            break;
        }
    }

    return 0;
}

总结select优缺点

在这里插入图片描述

copyright notice
author[Cola_Forever],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/218/202208061856509524.html

Random recommended