带有 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
,而不是在状态机中调用readpartial
。 read_nonblock
如果没有可读取的内容,将抛出异常,我可以捕获此异常并解除阻塞选择循环。
【讨论】:
以上是关于带有 nio4r 选择循环的 Ruby 套接字的主要内容,如果未能解决你的问题,请参考以下文章