微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Epoll TCP边缘触发的最后一次读取2调用的必要性

给定一个非阻塞的TCP套接字,如果调用

read(sock,buf,bufLen)

返回值< bufLen ,然后等待边缘触发的EPOLLIN事件是否安全? 或者我必须再次打电话read ,以确保它是零或EAGAIN?

在我的testing中,当我删除最后一个呼叫时,一切都保持工作状态,我只想知道是否在任何地方或Linux源代码保证,如果我可以摆脱额外的电话。

在Windows上的multithreading应用程序中阻塞服务器/侦听套接字的最佳方法

在Windows中比在Linux中慢的端口监听?

linux原生socket编程问题

何时调用setsockopt? bind()和connect()之前?

带recv-timeout的套接字:这段代码有什么问题?

在Linux上的Socket性能

Windows套接通知接收器

连接到本地虚拟机

在Debian上的Daemonize()问题

recv()失败:错误文件描述符c ++ Linux

你的问题在man 7 epoll回答。 如您所见,它取决于套接字类型(数据包/流):

Q9使用EPOLLET标志(边缘触发行为)时,是否需要不断读写文件描述符,直到EAGAIN?

A9从epoll_wait(2)接收一个事件应该向你建议这样的文件描述符已经准备好用于请求的I / O操作。 您必须考虑它,直到下一个(非阻塞)读取/写入产生EAGAIN。 何时以及如何使用文件描述符完全取决于您。

对于面向数据包/令牌的文件(例如,数据报套接字,规范模式下的终端),检测读/写I / O空间结束的唯一方法是继续读/写,直到EAGAIN。

对于面向流的文件(例如管道,FIFO,流套接字),还可以通过检查从目标文件描述符读取/写入的数据量来检测读/写I / O空间耗尽的情况。 例如,如果通过要求读取一定数量的数据来调用read(2),并且读取(2)返回较少的字节数,那么可以肯定已经耗尽了文件描述符的读取I / O空间。 使用写入(2)写入时也是如此 。 (如果不能保证受监视的文件描述符始终引用一个面向流的文件,请避免使用后一种技术。)

只要它不会崩溃 ,它是“安全的”,但除非继续调用read直到获得EAGAIN (或0,这意味着另一端已关闭连接),否则有时会对数据的可用性做出错误的假设。 最糟糕的是,它大部分时间看起来也能正常工作。

与级别触发的通知相比,边缘触发仅保证您在上次调用epoll_wait准备就绪状态发生更改时收到一个通知,即使存在您可以读取的数据。

边缘触发的事件通知在Linux下有时会表现出怪异或不直观,所以它可能会做一些与你期望的不同的东西,例如当更多的数据到达时给你另一个通知(所以你的代码似乎“工作不管”),但是不是什么保证。

在使用epoll和eventfd时,我有类似的“惊喜”。 在边缘触发模式下,你会发现所有已经被阻塞的线程都被唤醒(所有的线程都是同时发生的,而且只有一次),并且在事件之后调用epoll_wait每个epoll_wait被阻塞,直到事件被消耗, 再次发出信号。 它真正做的是唤醒叫做epoll_wait的第一个线程。 再次让人惊喜的是,电平触发模式的工作原理与您所期望的完全相同,除非您必须消耗事件才能够再次准备好,对此,没有正确的方法(因为您必须只做一次 ,会阻塞在read )。

因此,如果你不消耗所有的数据,等待再次得到通知,你可能是幸运的,它将“无论如何”,或者你可能会等待很长一段时间,可能永远。 因此,我的建议是, 一定要继续阅读,直到你得到EAGAIN ,这是唯一真正可靠的事情,以避免意外。

请注意,如果你保持天真的阅读,你可以挨饿慢发送者。 如果你有一个非常快的发件人,并且你继续阅读快速的发件人,那么你永远不会看到EAGAIN (至少不会EAGAIN另一端发送!),你会完全饿死其他发件人。

因此,将所有准备好的描述符放在一个列表中,然后循环读取它们,当它们返回EAGAIN时将它们从列表中删除

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐