[英]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.