epoll_wait总是设置EPOLLOUT位?

11 c sockets linux epoll

在侦听套接字上我设置了EPOLLIN位但是在客户端连接上我将EPOLLIN | EPOLLOUT位设置为struct 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)
     ...
Run Code Online (Sandbox Code Playgroud)

这就是我测试位的方式:

if ((events & EPOLLIN) == EPOLLIN)
     ...
if ((events & EPOLLOUT) == EPOLLOUT)
     ...
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

if (events & EPOLLIN)
     ...
if (events & EPOLLOUT)
     ...
Run Code Online (Sandbox Code Playgroud)

两种方式都是真的!

但是,每当我在epoll fd上调用epoll_wait时,返回的活动文件描述符ALWAYS都设置了两个位,即使send()没有返回EAGAIN但是当我尝试recv()时它返回EAGAIN.

当recv()返回EAGAIN时,我不知道我应该做什么,我应该删除EPOLLOUT标志还是什么?

@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));
}
Run Code Online (Sandbox Code Playgroud)

然后我调用epoll_wait():

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

Nik*_*sov 28

我觉得你倒退了.EPOLLOUT除非您EAGAIN从写入尝试获得,否则不要包括,并在成功将字节写入套接字时将其删除.

这基本上意味着只要套接字内核发送缓冲区中有空间,套接字总是可写的.

编辑0:

您有两个数据流 - 输入输出.

您正在等待输入,包括EPOLLIN在标志中.如果epoll_wait(2)没有设置从该标志返回,则在某个其他套接字上发生某个事件,或者此套接字有其他事件.除非您收到错误(意味着您仍然对套接字上的输入感兴趣),请将标志保留在事件中.

你不必等待输出(因为它是你的动作),你只需要写入套接字,但是如果你溢出套接字发送缓冲区,你EAGAIN将从send(2)或来write(2).在这种情况下,你开始等待输出是可能的(内核耗尽套接字发送缓冲区,从而为你发送更多的空间)包括EPOLLOUT.一旦得到,将挂起的输出字节写入套接字,如果成功,EPOLLOUT则从事件中删除.

现在EPOLLET表示边缘触发等待,这意味着您的所需事件只会在每次状态更改时发出一次信号(例如从"无输入"到"有输入").在这种模式下,你应该在循环中读取输入字节,直到你得到EAGAIN.

希望这可以帮助.

  • @ user9000如果要读取数据,设置EPOLLIN,并在返回true时读取数据,如果读取返回EAGAIN,请等到下一次.如果您要发送数据,请发送.如果发送返回EAGAIN和/或EWOULDBLOCK,则打开EPOLLOUT并在EPOLLOUT变为真时继续发送.如果您没有任何要发送的内容,请关闭EPOLLOUT.虽然您的代码很难看到您在哪个位置检查哪个结构,但您应该显示执行epoll_wait()的代码.EPOLLET很难做对,我建议你不要使用它,直到你完全100%理解epoll. (4认同)