clinuxsocketsnonblockingposix-select

read() in a loop with non-blocking socket only reads first 1024 bytes


The following code in socketRead() is being sent 32K bytes of data. However, only the first 1024 bytes are read. The socket is non-blocking. Am I using EWOULDBLOCK and EAGAIN improperly?

I would expect the code in socketRead() to keep looping reading the entire 32K bytes instead of stopping after reading only 1024 bytes. What am I doing wrong?

    int SetSocketNonBlocking(int socketfd)
    {
            return( fcntl(socketfd, F_SETFL, fcntl(socketfd, F_GETFL, 0) | O_NONBLOCK) );
    }


    int SocketReadReady(int sockfd, unsigned int timeoutSeconds)
    {
            fd_set set;
            struct timeval timeout;
            int retCode = 0;

            FD_ZERO(&set);
            FD_SET(sockfd, &set);

            timeout.tv_sec = timeoutSeconds;
            timeout.tv_usec = 0;

            while(1)
            {
                    retCode = select(sockfd+1, &set, NULL, NULL, &timeout);
                    if( (retCode == -1) && (errno == EINTR) )
                    {
                            continue;
                    }
                    else
                    {
                            break;
                    }
            }
            return( retCode == 1 );
    }



uint8_t *SocketRead(int sockfd, int *bytesRead)
{
        int size_recv = 0;
        int total_size = 0;
        uint8_t *data = NULL;


        // initially we will provide ourselves with a 275k buffer
        // which is more than large enough for a 3" x 8" rasterized image.
        data = malloc((size_t)READ_CHUNK_SIZE * 275);


        if( data != NULL )
        {
                if( SetSocketNonBlocking(sockfd) == -1 )
                {
                        printf("Failed setting non-blocking\n");
                }
                if( SocketReadReady(sockfd, 10) )
                {
                        printf("Socket ready for read\n");
                        do
                        {
                                // TODO: We need to at some point make sure to realloc() the buffer if we have to read more than
                                // 275k of data
                                size_recv =  recv(sockfd, (void *)&data[total_size], READ_CHUNK_SIZE, MSG_DONTWAIT);
                                if( size_recv < 0 )
                                {
                                        if( errno == EWOULDBLOCK )
                                        {
                                                break;
                                        }
                                        else if( errno == EAGAIN)
                                        {
                                                continue;
                                        }
                                }
                                else if( size_recv == 0 )
                                {
                                        // connection closed
                                        printf("Connection closed\n");
                                        break;
                                }
                                else
                                {
                                        total_size += size_recv;
                                }
                        }while(1);
                }
                else
                {
                        printf("Socket timed out waiting for data to read\n");
                }
        }

        *bytesRead = total_size;
        return data;
}

Solution

  • Thanks to all the comments. The following code works correctly now. It may need a bit of refinement, but it at least works.

    uint8_t *SocketRead(int sockfd, int *bytesRead)
    {
            int size_recv = 0;
            int total_size = 0;
            uint8_t *data = NULL;
    ​
    ​
            // initially we will provide ourselves with a 275k buffer
            // which is more than large enough for a 3" x 8" rasterized image.
            data = malloc((size_t)READ_CHUNK_SIZE * 275);
    ​
    ​
            if( data != NULL )
            {
                    if( SetSocketNonBlocking(sockfd) == -1 )
                    {
                            printf("Failed setting non-blocking\n");
                    }
                    if( SocketReadReady(sockfd, 10,0) )
                    {
                            printf("Socket ready for read\n");
                            do
                            {
                                    // TODO: We need to at some point make sure to realloc() the buffer if we have to read more than
                                    // 275k of data
                                    size_recv =  read(sockfd, (void *)&data[total_size], READ_CHUNK_SIZE);
                                    if( size_recv < 0 )
                                    {
                                            if( errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
                                            {
                                                    if( SocketReadReady(sockfd,0,100) )
                                                    {
                                                            continue;
                                                    }
                                                    else
                                                    {
                                                            break;
                                                    }
                                            }
                                            else
                                            {
                                                    perror("Socket read:");
                                                    if( data )
                                                    {
                                                            free(data);
                                                            data = NULL;
                                                    }
                                                    break;
                                            }
                                    }
                                    else if( size_recv == 0 )
                                    {
                                            // connection closed
                                            printf("Connection closed\n");
                                            break;
                                    }
                                    else
                                    {
                                            total_size += size_recv;
                                    }
                            }while(1);
                    }
                    else
                    {
                            printf("Socket timed out waiting for data to read\n");
                    }
            }
    ​
            *bytesRead = total_size;
            return data;
    }