4

epollの man ページには、次のようなエッジ トリガーのサンプル コードがあります。

for (;;) {
    nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
    if (nfds == -1) {
        perror("epoll_pwait");
        exit(EXIT_FAILURE);
    }

    for (n = 0; n < nfds; ++n) {
        if (events[n].data.fd == listen_sock) {
            conn_sock = accept(listen_sock,
                        (struct sockaddr *) &local, &addrlen);
            if (conn_sock == -1) {
                perror("accept");
                exit(EXIT_FAILURE);
            }
            setnonblocking(conn_sock);
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = conn_sock;
            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                    &ev) == -1) {
                perror("epoll_ctl: conn_sock");
                exit(EXIT_FAILURE);
            }
        } else {
            do_use_fd(events[n].data.fd);
        }
    }
}

関数 do_use_fd では、ブロックされていない recv を while ループで EAGAIN まで呼び出すと、サンプル コードは正常に動作します。

このサンプル コードについて質問があります。50 個のソケット クライアント接続があり、突然 10 個のクライアントが同時にデータを書き込むとします。そのため、epoll_wait() は 10 を返し、次に for ループに進みます。

for (n = 0; n < nfds; ++n)

これらの 10 個のクライアントを呼び出し do_use_fd(events[n].data.fd); ます。n=5 が完了し、n=6 がまだ完了していないとします。10 個のイベントがすべて完了し、epoll_wait に戻った後、突然、イベント n=3 のファイル記述が新しいデータを受け取りました。 、クライアントが読み取る新しいデータがあることを通知するイベントを取得できますか? または、イベントが発生したときにコードが epoll_wait にないため、見逃してしまいます!!

4

2 に答える 2

13

エラーが発生するまで読んでいる限りEAGAIN、次に を呼び出したときにイベントを取得できますepoll_wait

このイベントは、空と非空 (または の場合は満杯と非満杯EPOLLOUT) の間で変化があった場合にのみトリガーされますが、イベントが を介して配信されるまでその状態は維持されepoll_waitます。

多少関連する注意事項: イベントに登録しEPOLLINEPOLLOUT送信バッファーがいっぱいにならないと仮定すると、トリガーされるたびEPOLLOUTに返されるイベントにフラグが設定されます - https://lkml.org/lkml/2011を参照してください。詳細については、/11/17/234を参照してください。epoll_waitEPOLLIN

最後に、エッジ トリガー モードの正確な動作は、実際には使用されるソケットの種類に依存し、実際にはどこにも文書化されていません。少し前にいくつかのテストを行い、結果をここに文書化しました: http://cmeerw.org/blog/753.html#753 - つまり、データグラム ソケットの場合、予想よりも多くのイベントを取得する可能性があります。

于 2012-10-15T14:04:04.563 に答える
2

epoll で Edge Triggered を使用する場合、何かを読んで、このようにすることができます

int n = -1;
while (1)
{
    n = recv(fd, iobuf, init_buff_size, MSG_DONTWAIT);
    if (n > 0)
    {
        LOG(glogfd, LOG_TRACE, "fd[%d] recv len %d\n", fd, n);
        mybuff_setdata(&(curcon->recv_buff), iobuf, n); // this is my func
        if (n == init_buff_size)
        {
            LOG(glogfd, LOG_DEBUG, "fd[%d] need recv nextloop %d\n", fd, n);
            continue;
        }
        break;
    }
    if (n == 0)
    {
        LOG(glogfd, LOG_ERROR, "fd[%d] close %s:%d!\n", fd, ID, LN);
        return do_close(fd);
    }
    if (errno == EINTR)
    {
        LOG(glogfd, LOG_TRACE, "fd[%d] need recv again!\n", fd);
        continue;
    }
    else if (errno == EAGAIN)
    {
        LOG(glogfd, LOG_TRACE, "fd[%d] need recv next!\n", fd);
        modify_fd_event(fd, EPOLLIN);   // this is the KEY, add read again
        break;
    }
    else
    {
        LOG(glogfd, LOG_ERROR, "fd[%d] close %s:%d!\n", fd, ID, LN);
        return do_close(fd);
    }
}
于 2013-08-01T10:21:26.830 に答える