非阻塞模式下读取的部分读取

时间:2013-11-20 07:51:13

标签: c linux

在“Linux系统编程”一书的第34页上,给出了以下使用while循环正确处理部分读取以阻止读取的示例

ssize_t ret;

while (len != 0 && (ret = read(fd, buf, len)) != 0) {
    if (ret == -1) {
        if (errno == EINTR) 
            continue;
        perror("read");
        break;
    }

    len -= ret;
    buf += ret;
}

在下一页中,它给出了非阻塞读取的以下示例。此示例是否需要包含在while循环中以处理部分读取的可能性?

char buf[BUFSIZ];
ssize_t nr;

start:
nr = read(fd, buf, BUFSIZ);
if (nr == -1) {
    if (errno == EINTR)
        goto start; /* oh shush */
    if (erron == EAGAIN)
        /* resubmit later */
    else
        /* error */
}

2 个答案:

答案 0 :(得分:1)

通常,当代码可以(或打算)并行执行其他操作而不是等待输入(例如检查另一个文件或套接字)时,使用非阻塞IO。否则,一个简单的阻塞IO将执行与在文件上轮询读取相同的技巧,如Jlghtuse所述。但是,我不确定是否保证非阻塞IO返回所请求的确切字节数。作为一个安全的赌注,它可能会使用while循环。我认为一个可用的代码块可能看起来像:

char buf[BUFSIZ];
ssize_t nr;
char *bufp = buf;
ssize_t rdbyts = 0;

while(rdbyts < BUFSIZ) {
    nr = read(fd, bufp, (BUFSIZ - rdbyts));
    if (nr == -1) {
        if (errno == EINTR)
            continue; /* oh shush */
        else if (errno == EAGAIN)
            /* resubmit later - might be do
             * something else and come back
             * or just sleep. */
            do_some_work_or_sleep();
            continue;
        else
            /* error */
            break;
    } else if (nr < (BUFSIZ - rdbytes)) {
        bufp += nr;
        rdbyts += nr;
    }
}

答案 1 :(得分:0)

不,这个例子不需要循环包装。它使用goto语句(请参阅this answer以获取其使用的好例子。)

此示例显示非阻塞读取,这就是此代码与第一个不同的原因。请参阅第二个代码块之后的注释:

  

处理EAGAIN案例就像我们做了EINTR案例一样(带有goto   开始)没什么意义。我们不妨没用过非   阻止I / O.非阻塞I / O的目的是捕获EAGAIN和   做其他有用的工作。