加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

为什么在这种情况下read()块?(linux epoll)

发布时间:2020-12-13 23:26:41 所属栏目:Linux 来源:网络整理
导读:我是unix编程的新手,今天我正在尝试epoll但遇到问题. 在级别触发模式下,我认为包括Ctrl-D在内的每个新输入事件都会导致epoll_wait返回.它工作正常.但是当我输入像aaa这样的东西时,按下Ctrl-D,读取块.当我键入Ctrl-D时,它不会. 你能解释一下会发生什么吗? 我
我是unix编程的新手,今天我正在尝试epoll但遇到问题.

在级别触发模式下,我认为包括Ctrl-D在内的每个新输入事件都会导致epoll_wait返回.它工作正常.但是当我输入像aaa这样的东西时,按下Ctrl-D,读取块.当我键入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,"timeoutn");
            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 byten",rcnt);
                    continue;
                }
                // else print ascii
                fprintf(stdout,"ascii code: %dn",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设置为非阻塞,我发现虽然read()返回-1,但epoll_wait仍然告诉我有一个可读的事件.但是如果我只输入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,rcnt;
    char c;

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

    // set monitoring STDIN_FILENO 
    epoll_ctl(epfd,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);
            }
        } 
    }
    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读取块.

CTRL-D不发信号通知EOF,而是清除目前为止输入的数据. CTRL-D本身被认为是一个事件.但实际上没有数据可以提取出来
FD.并且鉴于套接字是阻塞的,我们最终会遇到读取在另一组事件发生之前没有返回的情况.

现在,如果CTRL-D是第一个事件,则通过读取yeilding零来识别它.发出EOF条件信号.如果有东西需要刷新,就不会发生这种情况.

当您使套接字无阻塞时,CTRL-D读取返回-1,并将errno设置为EAGAIN.这意味着’现在没有数据要读.等会再试’.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读