Asem Ka
Asem Ka

Reputation: 27

why socket is ready to read only after thousands of iterations?

I am writing my http server. I use select function and see that socket is ready to write any time, but can be read only after thousands of iterations. If I use select(Max+1, &rfd, NULL, NULL, NULL), I do not have such problem. Why it is ready to read only after so many iterations?

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++;
    }
}

Upvotes: 0

Views: 183

Answers (1)

Some programmer dude
Some programmer dude

Reputation: 409136

A socket will always be writable, unless you fill up its buffers.

So select will return immediately for every call, with all the sockets marked as writable.

Only add sockets to the write-set when you actually have something to write to them. And once you have written all you need, then remove them from the set and don't add them back (until the next time you need to write to the socket).


When you don't use the write-set, then select will simply not return until there's a socket active in the read-set.

Upvotes: 6

Related Questions