Ruby数据包缓冲和拆分



所以,我想这有点宽泛,但我会尽可能缩小范围。我有一个服务器(带EventMachine(,有时数据包是分开的,但有时它们是缓冲的。因此,我尝试创建一个函数来缓冲/取消缓冲它们。我确实做了一些东西,但它并没有像预期的那样工作老实说,我甚至怀疑我能称之为"几乎没有功能">

在做任何其他事情之前,我想指出数据包结构:

  • 数据包的前四个字节是它的ID或数据包的名称(name(
  • 接下来的四个字节是数据包(len(的"消息"部分的长度
  • msg部分之前的最后四个字节是一个参考字段,它有各种用途(ref(

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


缓冲程序代码

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语言制作的客户端,所以是的,它是一个字节流。

我不确定到底出了什么问题,但该方法似乎没有正确地分割或缓冲数据包。当它接收少量数据(我认为这些数据既没有缓冲也没有分割(时,它工作得很好。

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


我很确定我在这里搞砸了一些"逻辑"部分,但我就是搞不清楚它是什么。任何帮助都将不胜感激。

感谢

我突然想到一个错误:

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的新函数中。该功能将负责跟踪它所需的任何状态信息(例如,它希望下一步接收消息的哪一部分(,将字节组装成完整的消息,并将强制消息传递给更高级别的代码。process_byte函数将不知道字节是如何打包的,因此您将立即粉碎程序可能存在的某类错误。

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

好吧,有些人认为我找到了一种正确的方法,感谢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

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

最新更新