二进制数据的Erlang错误

时间:2012-10-16 15:55:32

标签: dns binary erlang

我刚刚开始了我的Erlang路径,我遇到了一个问题,我无法解决一个解决方案:

我写了一个metod来将一个域名称为二进制字符串,即<<“www.404pagenotfound.com”>>并根据DNS协议的要求将其转换为域格式,因此:<< 3,“www”,15,“pagenotfound”,3,“com”>>。

在下面的代码中(我以不同的方式重复多次):

domainbyte(Bin) ->
    if byte_size(Bin) > 0 ->
        Res =  binary:split(Bin, <<".">>),
        [Chunk|[RestList]] = Res, 
        ChunkSize = byte_size(Chunk),   
        if length(RestList) > 0 -> 
            Rest = domainbyte(RestList),  %% <- Got "bad argument" here!
            <<ChunkSize/binary,Chunk,Rest>>;
        true ->
            <<ChunkSize/binary,Chunk>>
        end
    end.

提前获取任何线索。

PS。

请注意我在代码abobe中发现了错误:

if length(RestList) > 0 -> %% here RestList is binary data so length throw "bad argument" error.

我用这种方式重新编写方法,但仍然没有运气:

**注意:我能够修复下面的代码,问题是如果你有一个二进制块并且你想在另一个二进制字符串中使用它,你必须在其上指定/ binary:一些不明显的东西我

即:考虑这个小代码片段:

**

TT =&lt;&lt;“com”&gt;&gt;, SS = <&lt; 3,TT,0&gt; %%&lt; - 你得到错误:坏参数

** 必须以这种方式修复: **

TT =&lt;&lt;“com”&gt;&gt;, SS =&lt;&lt;&lt;&lt;&lt; 3,TT / binary,0&gt;&gt;

domainbyte(Bin) ->
    if byte_size(Bin) > 0 ->
        Res =  binary:split(Bin, <<".">>),
                if length(Res) > 1 -> 
                    [Chunk|[RestList]] = Res, 
                    ChunkSize = byte_size(Chunk),
                    Rest = domainbyte(RestList),
                    <<ChunkSize,Chunk,Rest>>;
                true -> 
                    [Chunk] = Res,
                    ChunkSize = byte_size(Chunk), 
                    <<ChunkSize,Chunk>>
                end
    end.

MDP

3 个答案:

答案 0 :(得分:2)

我认为最简单的解决方案是使用二进制理解来定义函数:

domainbyte(Bin) ->
    Chunks = binary:split(Bin, <<".">>, [global]),      %A list of all the chunks
    << <<byte_size(C),C/binary>> || C <- Chunks >>.     %Build output binary

将输出二进制文件构建为单独函数中的段列表然后将它们放在iolist_to_binary/1中可能会稍快一些。请注意,如果是'。'在二进制文件中最外面发生,然后此代码将其作为长度为0的空段。如果这些应该被丢弃,那么您需要将选项trim添加到binary:split/3。另请注意,该大小仅占用一个字节。

@Alnitak具有单独的函数,但是在时间上构建二进制的一个段,因此它不会比执行相同操作的二进制理解更有效。

NB 如果构建二进制文件时有二进制段Chunk/binary,则表示Chunk IS 是二进制文件,而不是它应该成为一体。二进制是扁平结构,想想字节数组,所以一切都变成二进制。或者更确切地说是二进制文件。

编辑:虽然我看到我错过了应该在最后的0。这是留给读者的练习。

编辑:处于教学模式,除了构建二进制文件之外,编写好的 Erlang 代码的关键是理解模式匹配。你使用了一点,但可以做得更多:

domainbyte(Bin) ->
    case binary:split(Bin, <<".">>) of
        [Chunk,Rest] ->                       %There was a '.'
            RestBin = domainbyte(Rest),
            Size = byte_size(Chunk),
            <<Size,Chunk/binary,RestBin/binary>>;
        [Chunk] ->                            %This was the last chunk
            Size = byte_size(Chunk),
            <<Size,Chunk/binary,0>>           %Add terminating 0
end.

这基本上和你的代码一样,但是我们使用模式匹配来选择一个子句,而不仅仅是分开一个已知的结构。模式匹配是控制的基本方法,不仅在case中,而且在函数和receive中。这导致if被非常谨慎地使用。

现在我已经足够了。

答案 1 :(得分:1)

我在Erlang上有点生疏,但我认为你的问题是RestList是来自binary:split输出的一组数据块。

所以,当你以递归方式回到domainbyte时,它的格式错误。

另外 - 不要忘记终止NUL字节来表示根标签!

FWIW,这是我的工作版本:

label([]) ->
    << 0 >>;

label([H|T]) ->
    D = label(H),
    P = label(T),
    << D/binary, P/binary>>;

label(A) ->
    L = byte_size(A),
    << <<L>>/binary, A/binary>>.

domainbyte(A) ->
    Res = binary:split(A, <<".">>, [global, trim]),
    label(Res).

它正确地添加了一个尾随的NUL字节,并修剪了任何额外的尾随点。

答案 2 :(得分:0)

二进制文件的结尾应该写成:

<< <<ChunkSize>>/binary, Chunk/binary, Rest/binary>>
% and
<< <<ChunkSize>>/binary, Chunk/binary>>