Search code examples
clinuxsocketsfile-descriptorposix-select

Multiple read call of a socket fd with O_NONBLOCK set fails


I am using select(), and NONBLOCKING connection fd to accept connections and handle input and output. I am having some issue handling large data transfer of more than the buffer size. So for example here:

readCount = 1;
while(readCount > 0)
{
    // clear t_input to read new data from the fd
    memset(t_input, 0, CLIENT_INPUT_BUFF_LEN);

    // read data from the client connectionFd and since t_input is 1024 only
    // read that much
    readCount = read(iter->connectionFd, t_input, 1024);
    printf("<<< %d - %s >>> \n", errno, strerror(errno));

    if(readCount == -1)
    {
        if( errno == EAGAIN) 
            break;
    }

    iter->AppendInputData(t_input, readCount);
}

This doesn't work for large data. So when I transfer data that is less than 1024, The first read call successfully finishes and data is copied in the AppendInputData call. Since it's in a loop, the second read call returns -1, and set's errno to EAGAIN which then breaks the loop - all is good for this case.

However, in the case of larger than 1024 data, the second read calls fails again and errno is set to EAGAIN. The weird thing is, in debug mode, I don't see this behavior and the second or third read call returns fine and all data is collected. Can someone explain what might be happening?


Solution

  • Try something more like this instead:

    do
    {
        // read data from the client connectionFd and since t_input is 1024 only read that much
        readCount = read(iter->connectionFd, t_input, 1024);
    
        if (readCount == -1)
        {
            if (errno == EAGAIN) 
            {
                fd_set fd;
                FD_ZERO(&fd);
                FD_SET(iter->connectionFd, &fd);
    
                timeval tv;
                tv.tv_sec = 5;
                tv.tv_usec = 0;
    
                readCount = select(iter->connectionFd+1, &fd, NULL, NULL, &tv);
                if (readCount == 1)
                    continue;
    
                if (readCount == 0)
                {
                    printf("<<< timeout >>> \n");
                    break;
                }
            }
    
            printf("<<< %d - %s >>> \n", errno, strerror(errno));
            break;
        }
    
        if (readCount == 0)
        {
            printf("<<< disconnect >>> \n");
            break;
        }
    
        iter->AppendInputData(t_input, readCount);
    }
    while (true);