1

所以,我想这有点宽泛,但我会尽量缩小范围。我有一台服务器(带有 EventMachine),有时数据包会被拆分,但有时它们会被缓冲。所以,我尝试创建一个可以缓冲/取消缓冲它们的函数。我确实设法制作了一些东西,但是它没有“按预期”工作。老实说,我什至怀疑我什至可以称之为“几乎没有功能”。

首先,我想指出数据包结构:

  • 数据包的前四个字节是它的 ID,或数据包的名称 ( name)。
  • 接下来的四个字节是数据包的“msg”部分的长度(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 语言制作的客户端,所以是的,它是一个字节流。

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

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


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

谢谢

4

2 回答 2

1

好吧,这是一个跳出来的错误:

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

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

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

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

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

于 2011-07-03T02:15:15.313 回答
0

好的,有些人认为我想出了一个正确的方法,感谢大卫格雷森的所有帮助,因为他的回答消除了我的很多困惑/怀疑:

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

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

于 2011-07-03T10:24:45.207 回答