带有 nio4r 选择循环的 Ruby 套接字

Posted

技术标签:

【中文标题】带有 nio4r 选择循环的 Ruby 套接字【英文标题】:Ruby sockets with nio4r select loop 【发布时间】:2013-03-15 06:55:03 【问题描述】:

假设我有一个选择循环,其中包含一些我要从中读取的打开连接,并且我在每个连接上都附加了状态机,这些状态机旨在解析通过网络传输的一些内容并做正确的事情。因此,假设其中一个连接c 已准备就绪,并且选择循环将其交给状态机m 进行处理。我们想从连接中读取 10 个字节,我们将使用readpartial。不幸的是,我们只收到了 6 个字节,所以m 读取了 6 个字节并解除阻塞。下次循环将c 交给我们时,它还有 11 个字节。 m 仍处于上次选择循环交给我们 c 时的任何状态,并且知道它需要再读取 4 个字节,因此它使用 readpartial(4) 读取这 4 个字节,使用这些执行某种副作用操作现在在其缓冲区中的 10 个字节并传输到新状态。 m 仍然保持连接,因此此时它可以解除循环阻塞或开始执行新状态指示的操作,其中一项操作可能涉及readpartial。在这种情况下,正确的做法是继续处理连接,因为readpartial 不会阻塞。但是假设动作顺序是:接收 6 个字节,读取 6 个字节并解除阻塞,接收 4 个字节,读取 4 个字节并做一些事情。在这种情况下,将没有什么可读取的,因此如果状态机决定在连接上调用readpartial,那么它将阻塞选择循环,这是一种不希望的情况,在这种情况下,正确的做法是状态机解除阻塞并等待选择循环再次出现。

如果我不想阻塞选择循环并且不想在连接缓冲区中留下字节,那么解决这个问题的正确和有效的方法是什么?我已经查看了 Ruby 的 Socket 和 IO API,但我找不到一种方法可以告诉我是否有要阅读的内容。 read_nonblock 是一种潜在的探索途径,用于通过读取单个字节然后将其放回来测试流是否可读,但在我的测试中它的行为与预期不符,即 char = c.read_nonblock(1); c.ungetc(char); wire_data = c.read_partial(10) 甚至会导致 wire_data == char如果连接缓冲区中的缓冲区超过char

【问题讨论】:

【参考方案1】:

像往常一样写下我遇到的问题帮助我找到了解决方案。我可以直接调用read_nonblock,而不是在状态机中调用readpartialread_nonblock 如果没有可读取的内容,将抛出异常,我可以捕获此异常并解除阻塞选择循环。

【讨论】:

以上是关于带有 nio4r 选择循环的 Ruby 套接字的主要内容,如果未能解决你的问题,请参考以下文章

使用带有选择器的非阻塞模式下的 Java NIO 和 Unix 域套接字

闪存套接字策略

Ruby在recv时检测套接字关闭

ruby 在Ruby中尝试使用分叉和unix套接字

Ruby 和 Net::SCP 传输(套接字)的性能问题

Ruby 套接字未接收到所有消息