具有O_NONBLOCK设置的套接字fd的多次读取调用失败

时间:2014-09-19 23:11:52

标签: c linux sockets select file-descriptor

我正在使用select()NONBLOCKING连接fd来接受连接并处理输入和输出。我有一些问题处理大于缓冲区大小的大数据传输。例如这里:

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

这对大数据不起作用。因此,当我传输的数据小于1024时,第一个read调用成功完成,数据将在AppendInputData调用中复制。由于它处于循环中,第二个read调用返回-1,并将errno设置为EAGAIN然后打破循环 - 这一切都适用于此情况。

但是,如果数据大于1024,则第二次读取调用将再次失败,errno将设置为EAGAIN。奇怪的是,在调试模式下,我没有看到这种行为,第二次或第三次read调用返回正常,所有数据都被收集。有人可以解释可能发生的事情吗?

2 个答案:

答案 0 :(得分:2)

这是时机。您无法假设所有数据都会连续到达,并且只要您调用read(),或者当EAGAIN发生时,它将永远存在。习惯上调用select()告诉您何时可以读取数据。

您在调试模式下会遇到不同的行为,因为您正在改变时间。

答案 1 :(得分:2)

尝试更像这样的东西:

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);