简体   繁体   English

epoll_wait总是设置EPOLLOUT位?

[英]epoll_wait always sets EPOLLOUT bit?

On a listening socket I set the EPOLLIN bit however on client connections I set EPOLLIN | EPOLLOUT 在侦听套接字上,我设置了EPOLLIN位但是在客户端连接上我设置了EPOLLIN | EPOLLOUT EPOLLIN | EPOLLOUT bits to struct epoll_event like so: EPOLLIN | EPOLLOUTstruct epoll_event像这样:

struct epoll_event ev;

ev.data.fd = fd;
ev.events = EPOLLIN | EPOLLOUT;
if (epoll_ctl(evs->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
     ...

And this is how I test bits: 这就是我测试位的方式:

if ((events & EPOLLIN) == EPOLLIN)
     ...
if ((events & EPOLLOUT) == EPOLLOUT)
     ...

I've also tried like: 我也尝试过:

if (events & EPOLLIN)
     ...
if (events & EPOLLOUT)
     ...

Both ways are ALWAYS true! 两种方式都是真的!

However, whenever I call epoll_wait on my epoll fd, the active file descriptor returned ALWAYS has both bits set even though send() didn't return EAGAIN but when I try to recv() it returns EAGAIN. 但是,每当我在epoll fd上调用epoll_wait时,返回的活动文件描述符ALWAYS都设置了两个位,即使send()没有返回EAGAIN但是当我尝试recv()时它返回EAGAIN。

I have no idea what am I supposed to do when recv() returns EAGAIN, am I supposed to remove the EPOLLOUT flag or what? 当recv()返回EAGAIN时,我不知道我该怎么做,我应该删除EPOLLOUT标志还是什么?

More code as requested by @Nikolai N Fetissov: @Nikolai N Fetissov要求的更多代码:

static int get_active_fd(events *evs, int index, sstate_t *flags)
{
    uint32_t events = evs->events[index].events;
    int fd = evs->events[index].data.fd;;

    if ((events & EPOLLERR) == EPOLLERR || (events & EPOLLHUP) == EPOLLHUP) {
        close(fd);
        return -1;
    }

    if (events & EPOLLIN)
        *flags |= DATA_IN;

    return fd;
}

void sockset_add(events *evs, int fd)
{
    struct epoll_event ev;
    ...
    ev.data.fd = fd;
    ev.events = EPOLLIN;
    if (epoll_ctl(evs->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
        eprintf("sockset_add(): epoll_ctl(%d) returned an error %d(%s)\n",
                fd, errno, strerror(errno));
}

Then later where I call epoll_wait(): 然后我调用epoll_wait():

if (flags & DATA_IN) {
       /* try to read which is impossible because this is never set.  */

I think you got it backwards. 我觉得你倒退了。 Don't include EPOLLOUT unless you got EAGAIN from a write attempt, and remove it when you have successfully written bytes to a socket. 除非您从写入尝试获得EAGAIN ,否则不要包括EPOLLOUT ,并在成功将字节写入套接字时将其删除。

This basically means that socket is always writable as long as there's space in socket in-kernel send buffer. 这基本上意味着只要套接字内核发送缓冲区中有空间,套接字总是可写的。

Edit 0: 编辑0:

You have two data streams - input and output . 您有两个数据流 - 输入输出

You are waiting for the input by including EPOLLIN in the flags. 您正在等待输入, EPOLLIN是在标志中包含EPOLLIN If upon return from epoll_wait(2) that flag is not set, then either some event happened on some other socket, or this socket had some other event. 如果从epoll_wait(2)返回该标志未设置,则某个事件发生在某个其他套接字上,或者此套接字有其他事件。 Leave the flag in the events unless you get an error (meaning you are still interested in the input on the socket). 除非出现错误(意味着您仍然对套接字上的输入感兴趣),否则将该标志保留在事件中。

You don't have to wait for the output (since it's your action), you just write to the socket, but if you overflow socket send buffer, you'll get EAGAIN from send(2) or write(2) . 您不必等待输出(因为它是您的操作),您只需写入套接字,但如果溢出套接字发送缓冲区,您将从send(2)write(2)获得EAGAIN In this case you start waiting for output to be possible (kernel draining socket send buffer thus making room for you to send more) by including EPOLLOUT . 在这种情况下,您可以通过包含EPOLLOUT来开始等待输出(内核耗尽套接字发送缓冲区,从而为您发送更多内容)。 Once you get that, write your pending output bytes to the socket, and if you are successful, remove EPOLLOUT from the events. 完成后,将挂起的输出字节写入套接字,如果成功, EPOLLOUT事件中删除EPOLLOUT

Now EPOLLET indicates edge-triggered wait, meaning your desired event would only be signaled once per state change (like from "no input" to "there's input"). 现在, EPOLLET表示边缘触发等待,这意味着您的所需事件只会在每次状态更改时发出一次信号(例如从“无输入”到“有输入”)。 In this mode you are supposed to read input bytes in a loop until you get EAGAIN . 在此模式下,您应该在循环中读取输入字节,直到获得EAGAIN

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM