使用边沿触发模式时,必须将数据读入一个 recv 打电话,否则冒着其他插座的危险。此问题已在许多博客中撰写过,例如: Epoll从根本上被打破 。
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. } } } }
可以进一步改进此版本以避免扫描整个版本 events 每次迭代都有数组。
events
在你原来的帖子 do {} while(n > 0); 是不正确的,它会导致无限循环。我认为这是一个错字。
do {} while(n > 0);