匹配 Elixir 二进制文件中的多个部分以解析 HTTP/2.0 帧

Posted

技术标签:

【中文标题】匹配 Elixir 二进制文件中的多个部分以解析 HTTP/2.0 帧【英文标题】:Matching multiple parts in an elixir binary for parsing HTTP/2.0 frames 【发布时间】:2017-12-01 04:19:51 【问题描述】:

我发现了一种从二进制文件中匹配帧的快速方法。 长度匹配为整数,并且 c 部分(有效负载)具有与长度字段中声明的一样多的八位字节。 (前三个八位字节)

<<length::24, b::48, c::binary-size(length)>> <> rest = buffer

问题是要到达我的框架,我需要重新组合部件。

frame = <<length::24, b::48, c::binary>>

无论如何在原始匹配中分配帧变量。类似于以下内容。 虽然这个精确的版本不起作用

(frame = <<length::24, _::48, _::binary-size(length)>>) <> rest = buffer

编辑,或者像下面这样的语法也有意义

<< frame = <<length::24, _::48, _::binary-size(length)>>, rest::binary>>

【问题讨论】:

您可能已经知道这一点,但为了避免重新创建二进制文件,您可以使用:binary.part(buffer, 0, 3 + 6 + length):binary.part/3 将从原始的 buffer 创建一个子二进制文件,而不是分配一个新的二进制文件。 我不知道这听起来很有帮助,仍然需要两步来获得我想要的二进制文件,但可能很快 【参考方案1】:

AFAIK,完全不可能这样,但你可以声明一个方便的助手来避免重复输入:

def matcher(buffer)
  with <<length::24, b::48, c::binary-size(length), rest::binary>> <- buffer do 
    :ok, <<length::24, b::48, c::binary-size(length)>>, rest
  else
    other -> :error, other
  end
end

并像这样使用它:

:ok, frame, rest = matcher(buffer)

【讨论】:

谢谢,不想听起来忘恩负义,但我已经走到了这一步:-)。我想知道是否可以使用一条线,因为它可能性能更高。不创建和连接临时二进制文件【参考方案2】:

我不明白b::48 表示的标头的确切部分。

但无论如何,在性能方面考虑几件事很重要。

    返回帧二进制文件并不能提高性能。如果您已经解析了框架并且知道它是完整的,那么将其作为etf 表示形式返回。不要重新解析它。 一行不一定性能更好。这就是以某种方式组合和提取二进制部分。 函数定义中的模式匹配也非常高效,尽可能针对不同的代码路径进行匹配。

我不知道&lt;&gt; 的性能到底如何。我认为这只是简写,但即使它不同,它也可能足够高性能。

这段代码应该创建和链接二进制部分,而不应该创建任何新的二进制文件。因此,它实际上非常高效。

<<length::24, b::48, c::binary-size(length), rest::binary>> = buffer
frame = <<length::24, b::48, c::binary>>

如果您想了解我是如何处理此类数据的,请查看WebSockex.Frame

【讨论】:

您确定frame = &lt;&lt;length::24, b::48, c::binary&gt;&gt; 会共享原始二进制文件吗?我刚刚创建了一个包含单个帧的 1 MB 缓冲区,并创建了一个包含 100 个&lt;&lt;length::24, b::48, c::binary&gt;&gt; 的列表,我的内存使用量增加了 100MB。另一方面,如果我创建一个包含 100 个frame = :binary.part(buffer, 0, 9999999) 的列表,我的内存使用情况大致相同。 是的,但它是编译时优化。请参阅Erlang Binary Handling 页面上的匹配上下文

以上是关于匹配 Elixir 二进制文件中的多个部分以解析 HTTP/2.0 帧的主要内容,如果未能解决你的问题,请参考以下文章

[Elixir006]CSV(Comma-separated values)处理

Elixir 列表模式匹配 ~ 在使用列表模式匹配常量后得到 x

Elixir中的“? s”是什么意思?

Elixir模式匹配协议实现者

这个Elixir函数中的(反向)赋值匹配有什么意义?

将来自 JInterface Java 应用程序的二进制响应转换回 Elixir 中的字符串列表