简体   繁体   中英

accept returns 0 for 2nd, 3rd, etc client

I'm writting a simple socket server/client app. I run into interesting problem. In my server code I call accept on non-blocking socket like this

while ((res = accept(m_sd, NULL, 0)) >= 0) { // There are new clients
  ... // Saving res as fd etc
}

Everything works perfectly - when there is a client, accept returns a valid file descriptor. However when a first client disconnects and second client connect, accept returns 0 - which is a valid FD, howerver all operation on this descriptor fails. This happens also for the next clients - accept is returning 0. After random number of clients, acceptr returns a "valid" (non-zero) descritpor, and than it repeats.

Note: When there are no clients, accept returns -1 as expected with errno EAGAIN - which is completly fine. When accept returns zero, errno is not set.

What could cause such a weird behavior?

Here's how I create server socket:

     struct sockaddr_in serv_addr;
     m_sd = socket(AF_INET, SOCK_STREAM, 0);
     if (m_sd < 0){}
        //Handle error

     bzero((char *)&serv_addr, sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(port);
     int optval = 1;
     setsockopt(m_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);

     if (bind(m_sd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
         // Handle error
     }
     fcntl(m_sd, F_SETFL, O_NDELAY); // Make socket non-blocking

     listen(m_sd, 50);

And here's how I create client:

    int rc;
    struct sockaddr_in serveraddr;
    struct hostent *hostp;
    m_sd = socket(AF_INET, SOCK_STREAM, 0);
    if (m_sd < 0)
           // Handle error
    memset(&serveraddr, 0, sizeof(struct sockaddr_in));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(port);

    hostp = gethostbyname(hostname.c_str());
    if (hostp == NULL)
      // Handle error

    memcpy(&serveraddr.sin_addr, hostp->h_addr, sizeof(serveraddr.sin_addr));

    // connect to serveraddr
    rc = connect(m_sd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
    if (rc < 0)
      //Handle error
    //set to nonblocking
    fcntl(m_sd, F_SETFL, fcntl(m_sd, F_GETFL, 0) | O_NONBLOCK);

This is the code, where I wait for new data from any client:

    struct timeval tv;

    tv.tv_sec = 0;
    tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(timeout).count();

    fd_set rfds;
    FD_ZERO(&rfds);
    FD_SET(m_sd, &rfds);
    int end = m_sd;
    for (const auto& s : m_clients) {
        end = std::max(end, s.second.m_sd);
        FD_SET(s.second.m_sd, &rfds);
    }

    int retval = select(end + 1, &rfds, NULL, NULL, &tv);
    if (retval == -1) {
       // Error handling
    }
    return retval > 0; // There is pending data from client

Problem solved! I was accidentally closing fd 0 in my code, which caused this weird behaviour. Now everything works. Thanks for helping - you've showed me the right way

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM