【发布时间】:2021-04-10 06:57:25
【问题描述】:
我有 Erlang SSL TCP 套接字,它与另一方有永久的 TCP 连接, 我们使用类似于 ISO8583 协议的协议,前四个字节是 ASCII 编码的数据包大小。 基于 Erlang inet 文档 (https://erlang.org/doc/man/inet.html) 它只支持无符号整数作为数据包大小。
The header length can be one, two, or four bytes, and containing an unsigned integer in big-endian byte order.
现在我使用 gen_server handle_info,一旦我收到一个数据包,我会读取前四个字节,然后将其与二进制大小进行比较,如果二进制大小很小,我什么也不做,并将收到的二进制文件放入 LastBin 并等待其余的数据包如果数据包中有多个味精,我会多次调用 read_iso 数据包,如果我这样做是这样的,则简短示例:
handle_info({ConnType, _Socket, Bin}, {BSSl, BProtocol, Psize, OSocket, LastBin})
when ConnType =:= ssl; ConnType =:= tcp ->
logger:debug("mp_back:Got response from backend~w", [Bin]),
read_iso_packet(Bin, {BSSl, BProtocol, Psize, OSocket, LastBin})
end.
read_iso_packet(Bin, {BSSl, BProtocol, Psize, Socket, LastBin})
when size(<<LastBin/binary, Bin/binary>>) < 5 ->
{noreply, {BSSl, BProtocol, Psize, Socket, <<LastBin/binary, Bin/binary>>}};
read_iso_packet(Bin, {BSSl, BProtocol, Psize, Socket, LastBin})
when size(<<LastBin/binary, Bin/binary>>) > 4 ->
Packe_Size = get_packet_size(binary:part(<<LastBin/binary, Bin/binary>>, 0, 4)),
logger:debug("mp_back:packet_size==~w", [Packe_Size]),
logger:debug("mp_back:bin_size==~w", [size(Bin)]),
read_iso_packet(Packe_Size + 4 - size(<<Bin/binary, LastBin/binary>>),
Packe_Size,
<<LastBin/binary, Bin/binary>>,
{BSSl, BProtocol, Psize, Socket, LastBin}).
read_iso_packet(0, _Packe_Size, Bin, {BSSl, BProtocol, Psize, Socket, _LastBin}) ->
do_somthing(server_response, CSocket, Bin),
{noreply, {BSSl, BProtocol, Psize, Socket, <<>>}};
read_iso_packet(SS, Packe_Size, Bin, {BSSl, BProtocol, Psize, Socket, _LastBin})
when SS < 0 ->
do_somthing(server_response, CSocket, [binary:part(Bin, 0, Packe_Size + 4)]),
read_iso_packet(binary:part(Bin, Packe_Size + 4, byte_size(Bin) - (Packe_Size + 4)),
{BSSl, BProtocol, Psize, Socket, <<>>});
read_iso_packet(SS, _Packe_Size, Bin, {BSSl, BProtocol, Psize, Socket, _LastBin})
when SS > 0 ->
logger:debug("mp_back: Small data going to read next~w", [Bin]),
{noreply, {BSSl, BProtocol, Psize, Socket, Bin}}.
get_packet_size(Bin) ->
{ok, [A], _} = io_lib:fread("~16u", binary_to_list(binary:part(Bin, 0, 1))),
{ok, [B], _} = io_lib:fread("~16u", binary_to_list(binary:part(Bin, 1, 1))),
{ok, [C], _} = io_lib:fread("~16u", binary_to_list(binary:part(Bin, 2, 1))),
{ok, [D], _} = io_lib:fread("~16u", binary_to_list(binary:part(Bin, 3, 1))),
A * 1000 + B * 100 + C * 10 + D.
我的问题是:
- 有没有更好的方法来做到这一点?上次我犯了一个错误并多次阅读了一些消息(我修复了那个错误,但还没有在生产中测试我的代码,但在测试中似乎还可以)。当数据包大小为无符号整数时,Erlang 可以为我处理这个问题,但对 ASCII 编码的数据包大小没有成功。
- 我尝试使用 {active, once} 和 gen_tcp:recv 但它对我来说不能正常工作,这是一种更安全的方法吗?
- gen_server:handle_info 是否同步?
【问题讨论】: