C++ 使用epoll边缘触发器的套接字上的数据太多

C++ 使用epoll边缘触发器的套接字上的数据太多,c++,linux,sockets,networking,tcp,C++,Linux,Sockets,Networking,Tcp,场景是这样的:一个进程在几个套接字上使用epoll,所有套接字都设置为非阻塞和边缘触发;然后一个套接字上发生EPOLLIN事件,然后我们开始读取其fd上的数据,但问题是传入的数据太多,并且在while循环读取数据时,recv的返回值始终大于0。因此,应用程序停留在那里,读取数据,无法继续 你知道我该怎么处理吗 constexpr int max_events = 10; constexpr int buf_len = 8192; .... epoll_event events[max_even

场景是这样的:一个进程在几个套接字上使用epoll,所有套接字都设置为非阻塞和边缘触发;然后一个套接字上发生EPOLLIN事件,然后我们开始读取其fd上的数据,但问题是传入的数据太多,并且在while循环读取数据时,
recv
的返回值始终大于0。因此,应用程序停留在那里,读取数据,无法继续

你知道我该怎么处理吗

constexpr int max_events = 10;
constexpr int buf_len = 8192;
....

epoll_event events[max_events];
char buf[buf_len];
int n;
auto fd_num = epoll_wait(...);
for(auto i = 0; i < fd_num; i++) {
    if(events[i].events & EPOLLIN) {
        for(;;) {
            n = ::read(events[i].data.fd, buf, sizeof(buf));
            if (errno == EAGAIN)
                break;
            if (n <= 0)
            {
                on_disconnect_(events[i].data.fd);
                break;
            }
            else
            {
                on_data_(events[i].data.fd, buf, n);
            }
        }
    }
}
constexpr int max_事件=10;
constexpr int buf_len=8192;
....
epoll_事件事件[最大事件];
char buf[buf_len];
int n;
自动fd_num=epoll_wait(…);
用于(自动i=0;i如果(n在使用边缘触发模式时,必须在一个
recv
调用中读取数据,否则可能会导致其他套接字耗尽。许多博客都曾讨论过这个问题,例如

确保您的用户空间接收缓冲区至少与内核接收套接字缓冲区大小相同。这样,您可以在一次
recv
调用中读取整个内核缓冲区

此外,您还可以以循环方式处理就绪套接字,这样控制流就不会陷入一个套接字的
recv
循环中。如果用户空间接收缓冲区与内核缓冲区大小相同,则效果最佳。例如:

auto n = epoll_wait(...);
for(int dry = 0; dry < n;) {
    for(auto i = 0; i < n; i++) {
        if(events[i].events & EPOLLIN) {
            // Do only one read call for each ready socket
            // before moving to the next ready socket.
            auto r = recv(...);
            if(-1 == r) {
                if(EAGAIN == errno) {
                    events[i].events ^= EPOLLIN;
                    ++dry;
                }
                else
                    ; // Handle error.
            }
            else if(!r){
                // Process client disconnect.
            }
            else {
                // Process data received so far.
            }
        }
    }
}
auto n=epoll_wait(…);
对于(int-dry=0;dry
此版本可以进一步改进,以避免在每次迭代时扫描整个
事件



在你原来的帖子中
do{}while(n>0);
是不正确的,它会导致一个无休止的循环。我认为这是一个输入错误。

你收到了什么样的数据?通常你可以/应该在从套接字读取更多数据的同时处理已经收到的数据。最好是并行的。
中有什么?
在这里发布伪代码是不够的。这就是为什么我更喜欢级别触发的epoll,w每次读取一个有界的数据。请确保我的事件循环平均必须再勾选几次,但每次循环的持续时间都更加一致,这样我的应用程序的其余部分就不会饿死。@W是的,这是正确的,但由于epoll中注册了多个套接字,因此在不完成当前循环的情况下无法处理其他套接字的事件第一,这是主要的concern@EJP你是对的,我以后会把它做得更完整。我正在做
man-epoll
页面中提到的事情,阅读直到得到一个EAGAIN返回,但我从来没有得到过…@EJP
select
仅在级别触发模式下运行,这与这里无关。很难理解你的评论。@EJP
 poll
也不在边缘触发模式下运行。读取边缘触发的内容@EJP它通过不必在循环中多次调用同一套接字上的
recv
来解决问题。当更多数据在连续的
recv
调用之间到达套接字时,该循环可能是无止境的,这是OP观察到的问题.换句话说,您还没有发现可变范围问题。