在Erlang中添加二进制文件会添加神秘的位串

时间:2010-04-28 17:39:34

标签: erlang named-pipes tail

我想在命名管道上运行tail以便于进行一些二进制日志文件处理。问题是神秘数据被添加到流的开头。我通过使用打开的端口(open_port)启动erlang进程来运行我的测试,然后我使用另一个shell将bin捕获到命名管道中。

这是一个从端口获取数据的简单函数:

bin_from_tail() ->
  open_port({spawn,"/usr/bin/tail -F named_pipe"},
                             [binary,in,eof]),
  receive
  {_,{data,<<Data/binary>>}} -> Data
  end.

所以我有两种方法可以获取相同的数据......

  1. 创建命名管道

    mkfifo named_pipe

  2. 此命令将阻止,直到您从另一个shell运行“cat log.bin&gt; named_pipe”

    {ok,TailBin} = file:read_file(log.bin)。

  3. 使用erlang文件库将整个文件读入内存 FileBin = file:read_file(log.in)。

  4. 但是TailBin和FileBin不一样! TailBin在开头有一个神秘的120字节字符串:

    <<40,6,161,69,172,216,56,14,100,0,80,6,0,0,0>>
    

2 个答案:

答案 0 :(得分:2)

感谢关于无休止地循环cat /重启死端口的想法。似乎命名管道缓冲了一点点,所以如果端口打开得足够快,则编写器进程(另一个程序)不会崩溃!绝对有风险的东西,但就黑客来说......它有效。

因为所说的所有邮件列表帖子都是这样做的,所以没有例子就这样做,我将发布我的工作方式!如果有人想提供改进,请随时这样做。我的解决方案:

read() ->
  Port = open_port({spawn,"/bin/cat /path/to/pipe"},
                   [binary,in,eof]),
  do_read(Port).

do_read(Port) ->
  receive
    {Port,{data,<<Data/binary>>}} ->
      case do_something:with(Data) of
        ok ->
          io:format("G") % Good
        Any ->
          io:format("B") % Bad
      end;
    {Port,eof} ->
      read();
    Any ->
      io:format("No match fifo_client:do_read/1, ~p~n",[Any])
  end,
  do_read(Port).

答案 1 :(得分:1)

我发现在erlang之外发生了同样的事情。问题是 tail 试图向您显示文件的 end ,而不是整个文件。如果你在普通文件上使用它,任何写的都是新的,并由 -f 选取,但在这种情况下看起来像 tail 正在等待直到结束文件(通过管道传来的eof)然后显示最后10行(将二进制文件视为文本)。

tail -F -c 9999999

(假设你的日志是9999999字节或更少)可能会有效。

也许尝试使用 cat 而不是 tail -F ,这似乎对我有用。然后你只需要避免 cat 退出eof的事实,我认为你试图通过使用tail来避免。

所以一个shell脚本无休止地循环 cat ,也许?

或者让erlang重新启动关闭并在它死亡时重新创建端口,因为你无论如何都要获得eof信号。或者在进程退出时使用exit_status标志open_port进行信号通知,因此需要区分eof和进程退出。 (如果同时使用exit_status和eof,eof永远不会出现,使用 cat&lt; / dev / null 进行简短测试表明)