使用erlang实现简单的二进制通信协议

来源:转载

最近实现的一种简单的协议以及工具,主要用于客户端服务端通讯传输二进制数据时,协议的解包与封包,具体如下:首先定义协议的格式,主要由三部分组成:        数据长度(数据部分长度+协议号长度):4个字节        协议号:2个字节        数据部分:2进制数据数据部分如果是字符串需要先计算字符串的长度,占2个字节,之后再紧跟字符串内容,以上三个部分构成一个完整的数据包,每次客户端服务端将数据进行以上格式的封包解包进行通信。下面是对一个协议号为10000的协议进行封包的例子:客户端向服务端发送了三个数据:角色rid(4个字节),服务器srv_id(字符串),消息msg(字符串),根据以上定义的协议的打包方式如下,定义一个erlang函数:

pack(cli, 10000, {Rid, Srv_id, Msg}) ->

Data = <<Rid:32, byte_size(Srv_id):16, Srv_id/binary, byte_size(Msg):16, Msg/binary>>,

Packet = <<(byte_size(Data) + 2):32, 10000:16, Data/binary>>,

{ok, Packet}.

 之后客户端可能通过socket的方式将二进制数据包发送给服务端了。 假设服务器收到数据,开始对数据包进行解析, P0表示一个完整的包的数据部分,且是上面客户端打包的数据,协议号为10000号,接下来就是将P0进行解包, 对此我写了一个模块lib_proto,专门来解析二进制数据包。下面的解析过程就是针对协议号为10000的数据包进行解析:

unpack(srv, 10000, P0) ->

{Rid, P1} = lib_proto:read_uint32(P0),

{Srv_id, P2} = lib_proto:read_string(P1),

{Msg, _P3} = lib_proto:read_string(P2),

{ok, {Rid, Srv_id, Msg}}.

通过上面的方式就能将数据包解析出来,得到各个字段的值。下面是lib_proto的部分实现:

read_uint32(B0) when is_binary(B0)

andalso byte_size(B0) >= 4 ->

<<Int32:32, B1/binary>> = B0,

{Int32, B1};

read_uint32(_B0) -> error.

read_string(B0) when is_binary(B0)

andalso byte_size(B0) >= 2 ->

<<Len:16, B1/binary>> = B0,

case byte_size(B1) >= Len of

true ->

<<String:Len/binary, B2/binary>> = B1,

{String, B2};

false ->

error

end;

read_string(_B0) -> error.

以上就是使用erlang进行二进制数据包的解包与封包的应用,应该说erlang生来就对处理二进制数据进行了很好的封装,个人只是在此基础上进行简单应用而已。

分享给朋友:
您可能感兴趣的文章:
随机阅读: