Ruby数据包缓冲和分裂

时间:2011-07-03 01:30:01

标签: ruby buffer eventmachine

所以,我认为这有点宽泛,但我会尝试尽可能地缩小范围。我有一个服务器(使用EventMachine),有时数据包会被拆分,但有时它们会被缓冲。所以,我尝试创建一个缓冲/解缓冲它们的函数。我确实设法制作了一些东西,但它没有像预期的那样起作用。说实话,我怀疑我甚至可以称之为“功能不足”。

在此之前,我想指出数据包结构:

  • 数据包的前四个字节是它的ID,或者数据包的名称(name)。
  • 接下来的四个字节是数据包'msg'部分的长度(len)。
  • msg部分之前的最后四个字节是一个引用字段,它有各种用途(ref)。

注意:lenf是len的原始格式,所以是一个字符串,我认为它并不重要。


Bufferer代码

def split(data)
    if ($packet_buffer != "" && !$packet_buffer.nil?)
        data = $packet_buffer + data
        $packet_buffer = ""
    end
    last = 0
    packets = []
    loop do
        if data[last..-1].length < 8
            $packet_buffer = data[last..-1]
            break
        end
        name = data[last...last+=4]
        lenf = data[last...last+4]

        len = 0
        data[last...last+=4].each_byte {|b| len+=b}

        if !data[last+4..-1].nil? && data[last+4..-1].length < len
            $packet_buffer = data
            break
        end

        ref = data[last...last+=4]
        msg = data[last...last+=len]

        packets << (name << lenf << ref << msg)

        break if data[last..-1].nil?
    end
    packets
end

TLDR

如何在Ruby中拆分缓冲的缓冲区拆分数据包/数据(由EventMachine传递)?

更新:数据包通过TCP发送。数据来自用C语言编写的客户端,所以它是一个字节流。

我不确定到底出了什么问题,但该方法似乎没有正确拆分或缓冲数据包。它收到少量数据(没有缓冲或拆分,我假设),工作正常。

有时甚至成功分割数据包,如果它们被缓冲,但缓冲似乎根本不起作用


我很确定我在这里弄乱了一些“逻辑”部分,但是我无法弄清楚它是什么。任何帮助将不胜感激。

由于

2 个答案:

答案 0 :(得分:1)

这是一个突然出现在我身上的错误:

len = 0
data[last...last+=4].each_byte {|b| len+=b}

你没有指定存储长度的格式,但是如果它是一个小的endian整数,那么你应该像len = (len>>8) + (b<<24)这样做,而不是像现在这样只添加所有字节。如果len始终小于256,您当前的算法将正常工作。

这里可能隐藏着其他逻辑错误。我不喜欢你使用像data[last..-1].nil?这样令人困惑的表达;我会将它们重写为涉及data.lengthlast的简单不等式。

如果你想真正清理你的代码,那么我建议采用不同的方法:一次一个地将字节输入到一个名为process_byte的新函数中。该功能将负责跟踪它所需的任何状态信息(例如,它希望接下来接收的消息的哪一部分),将字节组装成完整的消息,并将complete消息传递给更高级别的代码。 process_byte函数不知道字节是如何打包的,所以你就可以立即粉碎程序可能存在的某类错误。

您可以使用Ruby光纤以一种很好的方式实现process_byte函数,允许您编写看起来同步的代码(例如len += get_next_byte())但实际上是异步的。

答案 1 :(得分:0)

好吧,有些人认为我找到了正确的方法,多亏了David Grayson的帮助,因为他的答案清除了我的许多困惑/怀疑:

def split(data)
    packets = []
    loop do
        if !$packet_buffer.nil?
            data = $packet_buffer << data
            $packet_buffer = nil
        end

        if data.length < 8
            $packet_buffer = data
            break
        end


        len = calc_Uint32(data[4...8])

        if data.length-12 < len
            $packet_buffer = data
            break
        end

        packets << data[0...12+len]
        data[0...12+len] = ''

        break if data.length == 0
    end
    packets
end #split

我真诚地怀疑任何人都会觉得它有用,因为它不是那么普遍,但我希望有人能最终找到它的用途。