用Erlang匹配二进制模式

2020-05-02 18:01:46

在Erlang中,很容易构建二进制文件和位串并匹配二进制模式。我遇到了Mitchell Perilstein与Erlang在NTP方面的出色工作,我想我要用这个来解释一下位串和二进制在Erlang中是如何工作的。

位串是零个或多个位的序列,其中位数不需要被8整除。

每个元素指定位串的某一段。段是二进制的一组连续位(不一定在字节边界上)。

让我们来了解一下这里正在发生的事情。为此,有必要了解整个语法。

这意味着在实际示例中,我们使用0作为值,2作为大小(2位),4作为值,3位作为大小,依此类推。我们没有指定任何类型说明符。

TypeSpecifierList是由连字符或破折号(-)分隔的任意顺序的类型说明符的列表。任何省略的类型说明符都使用默认值。

type=INTEGER|FLOAT|BINARY|BYTES|BITRING|BITS|UTF8|UTF16|UTF32。

默认值为整数。字节是二进制的速记,BITS是位串的速记。

它只在匹配和类型为整数时才重要。默认值为无符号。

Native-endian意味着在加载时将字符顺序解析为大端或小端,具体取决于运行Erlang机器的CPU的本机字符顺序。仅当类型为整型、utf16、utf32或浮点型时,字节序才重要。默认值为大。

目前最简单的协议之一是NTP。头文件如下所示:

它同时用于请求和响应。让我们先起草一下请求吧。

根据头结构,我们可以看到我们有2位整数(LI)、3位整数版本号、3位整数模式、8位层、8位轮询、8位精度等等。我们只需要设置前3个值,其余的(376位)可以设置为0。

我们可以使用Erlang的内置函数来实现这个,gen_udp有一个相当全面的低级UDP实现,可以做我们想做的一切。

%打开本地套接字,0表示它将选择随机本地端口%active=false表示我们需要接收自己的2&>;{ok,socket}=gen_udp:open(0,[binary,{active,false}]),2&>;gen_udp:send(socket,";0.europe.pool.ntp.org";,123,request),2&>。{OK,{_ADDRESS,_PORT,RESP}}=gen_udp:recv(套接字,0,500)。{OK,{{212,59,0,1},123,<;<;;36,2,0,231,0,0,0,110,0,0,0,25,212,59,3,3,226,84,62,89,208,192,202,156,.>;>;}。

响应只是一个我们需要分割的二进制文件,类似于我们创建请求的方式。

4>;<;<;LI:2,版本:3,模式:3,_REST/BINARY>;>;=Resp。<;36,2,0,231,0,0,0,110,0,0,0,25,212,59,3,3,226,84,62,89,208,192,202,156,0,0,0,0,.>;>;5>;{li,li,version,version,mode,mode}。{li,0,版本,4,模式,4}。

头的其余部分有点棘手,但是使用位串语法,它很容易管理。

6>;<;<;LI:2,版本:3,模式:3,分层:8,轮询:8/有符号,精度:8/有符号,6&gT;根目录:32,根磁盘:32,R1:8,R2:8,R3:8,R4:8,RTSI:32,RtsF:32,6>;OTSI:32,OtsF:32,RcvI:32,RcvF。=响应。<;<;36,2,0,231,0,0,0,110,0,0,0,25,212,59,3,3,226,84,62,89,208,192,202,156,0,0,0,0,.>;>;>;

理解这些价值需要更多的跑腿工作。首先,我们需要一个二进制分数的效用函数。

b基础设施(Bin)->;b基础设施(Bin,2,0)。b基础设施(0,_,Frac)->;Frac;b基础设施(Bin,N,Frac)->;b基础设施(Bin BSR 1,N*2,Frac+(Bin Band 1)/N)。

使用此函数,我们可以实现处理响应并返回感兴趣的值的函数。

%2208988800是偏移量(1900年到UNIX纪元)PROCESS_ntp_RESPONSE(Ntp_RESPONSE)->;<;<;LI:2,版本:3,模式:3,分层:8,轮询:8/有符号,精度:8/有符号,RootDel:32,RootDisp:32,R1:8,R2:8,R3:8,R4:8,RTSI:32,RtsF:32,OTSI:32,OtsF:32,RcvI:32,RcvF:32,XmtI:32,XmtF:32>;=NTP_RESPONSE,{NowMS,NOWS,NowUS}=Erlang:Timestamp(),NowTimestamp=NowMS*1。0 e6+NOWS+NOWUS/1000,传输时间戳=XMTI-2208988800+BINFIC(XMTF),{{li,li},{vn.。

{{li,0},{vn,4},{模式,4},{层,2},{轮询,3},{精度,-24},{根延迟,9},{根分散,140},{引用ID,85,158,25,75},{引用时间戳,1588186010。75