所以,我想这有点宽泛,但我会尽可能缩小范围。我有一个服务器(带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.length
和last
的简单不等式。
如果你想真正清理你的代码,那么我建议你采取一种不同的方法:将字节一次一个地输入到一个名为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
我真诚地怀疑有人会觉得它有用,因为它并不是那么普遍,但我希望最终有人能找到它的用途。