为什么套接字在数千次迭代后才准备好读取?

Ase*_* Ka 0 c++ sockets select

我正在编写我的http服务器。我使用 select 函数,发现套接字已准备好随时写入,但只能在数千次迭代后才能读取。如果我使用 select(Max+1, &rfd, NULL, NULL, NULL),我就没有这样的问题。为什么经过这么多次迭代之后才准备好读取?

int iteration = -1;
while (true)
{
    iteration++;
    FD_ZERO(&rfd);
    FD_ZERO(&wfd);
    FD_SET(listeningSocket, &rfd);
    for (std::set<int>::iterator Iter = servingSockets.begin(); Iter != servingSockets.end(); Iter++)
    {
        FD_SET(*Iter, &rfd);
        FD_SET(*Iter, &wfd);
    }
    int Max = std::max(listeningSocket, *std::max_element(servingSockets.begin(), servingSockets.end()));
    res = select(Max + 1, &rfd, &wfd, NULL, NULL);
    if (res <= 0)
        continue;

    if (FD_ISSET(listeningSocket, &rfd))
    {
        if ((newSocket = accept(listeningSocket, (struct sockaddr *)&listeningSocketAddr, (socklen_t *)&listeningSocketAddr)) < 0)
            continue;
        fcntl(newSocket, F_SETFL, O_NONBLOCK);
        servingSockets.insert(newSocket);
    }

    for (std::set<int>::iterator Iter = servingSockets.begin(); Iter != servingSockets.end();)
    {
        if (FD_ISSET(*Iter, &rfd))
        {
            std::cout<<"iter in loop: "<<iteration<<std::endl;
            int bytes_recvd = recv(*Iter, request, request_buffer_size - 1, 0);
            if (bytes_recvd < 0)
            {
                fprintf(stderr, "error recv\n");
                shutdown(*Iter, SHUT_RDWR);
                close(*Iter);
                servingSockets.erase(*Iter);
                continue;
            }
            request[bytes_recvd] = '\0';
            parse_http_request(request, &req);
        }
        if (FD_ISSET(*Iter, &wfd) && req.path[0] != '\0')
        {
           
            send(*Iter, "HTTP/1.1 200 OK\n\n<h1><a href=\"\">external</a><br><a href=\"internal\">internal</a></h1>", 122, 0);
            shutdown(*Iter, SHUT_RDWR);
            close(*Iter);
            Iter = servingSockets.erase(Iter);
            continue;
        }
        Iter++;
    }
}
Run Code Online (Sandbox Code Playgroud)

Som*_*ude 6

套接字始终是可写的,除非您填满了它的缓冲区。

因此select每次调用都会立即返回,并将所有套接字标记为可写。

仅当您确实有东西要写入时,才将套接字添加到写入集中。一旦您写入了所需的所有内容,请将它们从集合中删除,并且不要将它们添加回来(直到下次需要写入套接字时)。


当您不使用写入集时,则select在读取集中有一个活动的套接字之前,将不会返回。