所以,我认为这有点宽泛,但我会尝试尽可能地缩小范围。我有一个服务器(使用EventMachine),有时数据包会被拆分,但有时它们会被缓冲。所以,我尝试创建一个缓冲/解缓冲它们的函数。我确实设法制作了一些东西,但它没有像预期的那样起作用。说实话,我怀疑我甚至可以称之为“功能不足”。
在此之前,我想指出数据包结构:
name
)。len
)。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
如何在Ruby中拆分缓冲的和缓冲区拆分数据包/数据(由EventMachine传递)?
更新:数据包通过TCP发送。数据来自用C语言编写的客户端,所以它是一个字节流。
我不确定到底出了什么问题,但该方法似乎没有正确拆分或缓冲数据包。它收到少量数据(没有缓冲或拆分,我假设),工作正常。
有时甚至成功分割数据包,如果它们被缓冲,但缓冲似乎根本不起作用
我很确定我在这里弄乱了一些“逻辑”部分,但是我无法弄清楚它是什么。任何帮助将不胜感激。
由于
答案 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.length
和last
的简单不等式。
如果你想真正清理你的代码,那么我建议采用不同的方法:一次一个地将字节输入到一个名为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
我真诚地怀疑任何人都会觉得它有用,因为它不是那么普遍,但我希望有人能最终找到它的用途。