Ruby 数据包缓冲和分割
所以,我想这有点宽泛,但我会尽力缩小范围。我有一个服务器(带有 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 传递)?
更新:
我不确定到底出了什么问题,但该方法似乎没有正确分割或缓冲数据包。当它接收少量数据时(我认为这些数据既没有缓冲也没有分割),它工作得很好。
有时它甚至可以成功分割数据包,如果它们被缓冲,但缓冲似乎根本不起作用
我相当确定我在这里弄乱了一些“逻辑”部分,但是我只是不明白它是什么是。任何帮助将不胜感激。
谢谢
So, this is a little broad, I suppose, but I'll try and narrow it down as much as I can. I have a server (with EventMachine) and sometimes the packets come split, but sometimes they're buffered. So, I tried creating a function that would buffer/un-buffer them. I did manage to make something, however it's not working 'as expected.' To be quite honest, I doubt I can even call it 'barely functional.'
Before anything else, I'll like to point out the packet structure:
- First four bytes of the packet are it's ID, or the name of the packet (
name
). - The next four bytes are the length of the 'msg' part of the packet (
len
). - And the last four bytes before the msg part is a reference field, which has various uses (
ref
).
Note: lenf
is the raw format of len, so a string, it's not that important, I think.
The Bufferer Code
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
How to split buffered and buffer split packets/data (passed by EventMachine) in Ruby?
Update: The packets are sent over TCP. The data comes from a client made in C, so yeah it is a stream of bytes.
I am not sure what exactly is going wrong, but the method doesn't seem to split or buffer the packets properly. It works fine while it receives small amounts of data (which aren't either buffered or split, I assume).
Sometimes it even splits packets successfully, if they're buffered, but buffering doesn't seem to work at all
I'm fairly sure I'm messing up some 'logic' part here, however I just can't figure out what it is. Any help will be greatly appreciated.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好吧,这是一个让我跳出来的错误:
您没有指定存储长度的格式,但如果它是一个小端整数,那么您应该执行类似
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() ),但实际上是同步的异步。
Well here's one error that jumps out at me:
You didn't specify what format you are storing the length in, but if it's a little endian integer then you should do something like
len = (len>>8) + (b<<24)
instead of just adding all the bytes together like you are doing now. Your current algorithm would work fine iflen
was always less than 256.There may be other logic errors hiding in here. I don't like your use of confusing expressions like
data[last..-1].nil?
; I would rewrite them as simple inequalities involvingdata.length
andlast
.If you want to really clean up your code then I would recommend taking a different approach: feed the bytes in to a new function called
process_byte
one at a time. That function would be in charge of keeping track of any state information it needs (e.g. what part of the message it is expecting to receive next), assembling the bytes into complete messages, and passing the compelete message on to higher-level code. Theprocess_byte
function would be unaware of how the bytes were packetized, so right away you will crush a certain class of bugs your program might have.You could use Ruby fibers to implement the
process_byte
function in a nice way that allows you to write code that looks synchronous (e.g.len += get_next_byte()
) but would actually be asynchronous.好吧,我想出了一种正确的方法,感谢大卫·格雷森的帮助,因为他的回答消除了我的很多困惑/疑虑:
我真诚地怀疑有人会发现它有用,因为它不是那么普遍,但我希望最终有人能找到它的用途。
Okay, some thinking I figured a way to do it properly, thanks to David Grayson for all his help, since his answer cleared a lot of confusions/doubts I had:
I sincerely doubt anyone will find it useful, since it's not that universal, but I hope someone can find an use for it, eventually.