簡體   English   中英

為什么在這種情況下read()會阻塞?(Linux epoll)

[英]Why does the read() block in this case?(linux epoll)

我是unix programming新手,今天我正在嘗試epoll但遇到了問題。

level-triggered模式下,我認為每個新輸入事件(包括Ctrl-D都會導致epoll_wait返回。 工作正常。 但是,當我鍵入aaa ,請Ctrl-D ,然后read塊。 當我鍵入Ctrl-D ,沒有。

你能解釋一下會發生什么嗎?

epoll_wait完成並根據fd准備好時,我應該讀取所​​有數據嗎?

謝謝!

#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

int main(int argc, const char *argv[]) {
    // create event
    struct epoll_event stdin_ev, events[10];

    // set event
    stdin_ev.events = EPOLLIN;
    stdin_ev.data.fd = STDIN_FILENO;

    // create epoll
    int epfd = epoll_create(1), i, rcnt;
    char c;

    // set monitoring STDIN_FILENO 
    epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev);

    while(1) {
        int ret = epoll_wait(epfd, events, 1, 1000);

        // timeout or failed
        if(ret == 0) {
            fprintf(stdout, "timeout\n");
            continue;
        } else if (ret < 0) {
            perror("ret<0");
            exit(EXIT_FAILURE);
        }

        // readable
        fprintf(stdout, "%d event(s) happened...\n", ret);
        for(i=0; i < ret; i++) {
            if(events[i].data.fd == STDIN_FILENO &&\
               events[i].events&EPOLLIN) {
                // read a char
                rcnt = read(STDIN_FILENO, &c, 1); 
                // if read 0 char, EOF?
                if(rcnt != 1) {
                    fprintf(stdout, "read %d byte\n", rcnt);
                    continue;
                }
                // else print ascii
                fprintf(stdout, "ascii code: %d\n", c);
            }
        } 
    }
    close(epfd);
    return 0;
}

輸入: aaa + Ctrl-D ,結果:

timeout
aaa // <-- `aaa`+`Ctrl-D`
1 event(s) happened...
ascii code: 97
1 event(s) happened...
ascii code: 97
1 event(s) happened...
ascii code: 97
1 event(s) happened...
^C // <-- read block here, `Ctrl-C` to kill

然后,我嘗試將STDIN_FILENO設置為非阻塞,並且我發現epoll_wait仍然告訴您有一個可讀事件,盡管read()返回-1。 但是,如果我只鍵入Ctrl-D ,則read()返回0。

#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

int set_nonblock(int sfd) {
    int flags, s;
    flags = fcntl(sfd, F_GETFL, 0);
    if(flags == -1) {
        perror("fcntl");
        return -1;
    }
    flags |= O_NONBLOCK;
    s = fcntl(sfd, F_SETFL, flags);
    if(s == -1) {
        perror("fcntl");
        return -1;
    }
    return 0;
}

int main(int argc, const char *argv[]) {
    // create event
    struct epoll_event stdin_ev, events[10];

    // set event
    stdin_ev.events = EPOLLIN;
    stdin_ev.data.fd = STDIN_FILENO;

    // create epoll
    int epfd = epoll_create(1), i, rcnt;
    char c;

    // set nonblocking
    if(set_nonblock(STDIN_FILENO) != 0) {
        exit(EXIT_FAILURE);
    };

    // set monitoring STDIN_FILENO 
    epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev);

    while(1) {
        int ret = epoll_wait(epfd, events, 1, 1000);

        // timeout or failed
        if(ret == 0) {
            fprintf(stdout, "timeout\n");
            continue;
        } else if (ret < 0) {
            perror("ret<0");
            exit(EXIT_FAILURE);
        }

        // readable
        fprintf(stdout, "%d event(s) happened...\n", ret);
        for(i=0;i < ret;i++) {
            if(events[i].data.fd == STDIN_FILENO &&\
               events[i].events&EPOLLIN) {
                // read a char
                rcnt = read(STDIN_FILENO, &c, 1); 
                // if read 0 char, EOF?
                if(rcnt != 1) {
                    fprintf(stdout, "read %d byte\n", rcnt);
                    continue;
                }
                // else print ascii
                fprintf(stdout, "ascii code: %d\n", c);
            }
        } 
    }
    close(epfd);
    return 0;
}

結果:

timeout
1 event(s) happened... // <-- `Ctrl-D`
read 0 byte // <-- read() -> 0
timeout
timeout
aaa // `aaa`+`Ctrl-D`
1 event(s) happened...
ascii code: 97
1 event(s) happened...
ascii code: 97
1 event(s) happened...
ascii code: 97
read -1 byte // `EPOLLIN` still happens.
timeout
^C

據我了解的行為:

如果您鍵入ENTER而不是ctrl-D,則會報告4個事件,如CTRL-D一樣。 我們看到ascii代碼:10作為換行符。 使用CTRL-D read塊。

CTRL-D並不是在發送EOF信號,而是清除到目前為止已輸入的數據。 CTRL-D本身被視為事件。 但是實際上沒有數據可以在該FD上提取。 鑒於套接字正在阻塞 ,我們最終會遇到在另一組事件發生之前read不返回的情況。

現在,如果CTRL-D是第一個事件,則識別為read零。 發出EOF狀態信號。 如果有要沖洗的東西,則不會發生這種情況。

使套接字成為非阻塞狀態時,CTRL-D read返回-1,而errno設置為EAGAIN。 這意味着“現在沒有數據可讀取。 等會再試'。

從手冊( epoll_ctl ):

EPOLLERR
    Error condition happened on the associated file descriptor.
    epoll_wait(2) will always wait for this event;
    it is not necessary to set it in events.

如您所見,錯誤情況始終受到監視。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM