【问题标题】:Ruby packet buffering and splittingRuby 数据包缓冲和拆分
【发布时间】:2011-07-03 01:30:00
【问题描述】:

所以,我想这有点宽泛,但我会尽量缩小范围。我有一台服务器(带有 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 语言制作的客户端,所以是的,它是一个字节流。

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

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


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

谢谢

【问题讨论】:

  • 通过互联网发送这些“数据包”的协议是什么?据我所知,TCP/IP 使用数据包,但它向用户公开的接口看起来像字节流。
  • 另外,如果您简化代码并尝试向我们解释出了什么问题,这将是一个更好的问题。
  • 数据包是通过 TCP 发送的,是的。数据来自一个用 C 语言制作的客户端(旧服务器也是如此,我正在尝试重新创建它),所以是的,它是一个字节流。我不确定到底出了什么问题,但该方法似乎没有正确拆分或缓冲数据包。它在接收少量数据时工作正常(我假设这些数据既不是缓冲的也不是拆分的)。有时它甚至可以成功拆分数据包,如果它们被缓冲,但缓冲似乎根本不起作用

标签: ruby buffer eventmachine


【解决方案1】:

嗯,这是一个让我跳出来的错误:

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

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

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

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

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

【讨论】:

    【解决方案2】:

    好的,有些人认为我想出了一个正确的方法,感谢 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
    

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

    【讨论】:

    • 你让我们挂在 calc_Uint32
    • @Glennular 它只会将 32 位无符号整数(小端序)转换为 Ruby Fixnum。此代码甚至不再使用,但如果您需要,我可以挖掘它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    相关资源
    最近更新 更多