我是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
返回-1,但read()
仍然告诉可读事件。但如果我只输入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
答案 0 :(得分:1)
据我了解行为:
如果您输入&#39; ENTER&#39;而不是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。这意味着现在无法读取数据。稍后试试&#39;。
答案 1 :(得分:0)
从手册(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.
如您所见,始终会监控错误情况。