[erlang-questions] struggling with port_command()

Gregory Haskins gregory.haskins@REDACTED
Fri Oct 22 22:58:45 CEST 2010


On Oct 22, 2010, at 10:26 AM, Hynek Vychodil wrote:

> On Thu, Oct 21, 2010 at 10:39 PM, Gregory Haskins
> <gregory.haskins@REDACTED> wrote:
>> Hi All,
>> 
>> I've been struggling all afternoon with what is perhaps a completely trivial problem, but I can't seem to get past it.
>> 
>> Ultimately, I want to be able to have a simple external port program transform a string (XML, in fact, but that shouldn't matter).  So I want to have my erlang program pump a string in on stdin, and then get a string back out on stdout.  Simple stuff, but it just will not work for me.
>> 
>> I scoured the net for examples and/or threads on problems in doing this, but was unable to figure out what I am doing wrong.  Here is an escript which exemplifies the issue:
>> 
>> #!/usr/bin/env escript
>> 
>> pipe_stdin(Port) ->
>>    case io:get_line("") of
>>        eof ->
>>            %port_close(Port),
>>            ok;
>>        Data ->
>>            true = port_command(Port, Data),
>>            pipe_stdin(Port)
>>    end.
>> 
>> main([Cmd]) ->
>>    io:format("Executing ~s~n", [Cmd]),
>>    Port = erlang:open_port({spawn, Cmd}, [stream, use_stdio, exit_status]),
>> 
>>    ok = pipe_stdin(Port),
>>    {ok, _Status, Output} = cmd_receive(Port, ""),
>> 
>>    io:format("-----~s~n", [Output]),
>> 
>>    ok.
>> 
>> cmd_receive(Port, Acc) ->
>>    receive
>>        {Port, {data, Data}} ->
>>            cmd_receive(Port, string:concat(Acc, Data));
>>        {Port, {exit_status, Status}} ->
>>            {ok, Status, Acc};
>>        Else ->
>>            throw({unexpected_msg, Else})
>>    end.
>> 
>> The problem I am seeing is that the data never seems to reach the port program (with or without the port_close()).  I pump the data in with port_command() and it returns "true" but nothing seems to come out the other side.  Any help would be greatly appreciated.
>> 
>> -Greg
>> 
>> PS: As a secondary question, is the right way to signal EOF on the stdin to the port to use port_close()?
> 
> 1> Port = open_port({spawn, "cat"}, [stream]).
> #Port<0.522>
> 2> port_command(Port, "Hello World\n").
> true
> 3> flush().
> Shell got {#Port<0.522>,{data,{eol,"Hello World\n"}}}
> ok
> 4> port_close(Port).
> true
> 
> Are you sure that data doesn't arrive to your port program?

It turns out it was, but I was misdiagnosing the issue.

> It seems
> that your port program is unable detect end of input data because
> there is not possible send eof (or I don't know how). When you use
> stream option it is up to you implement correct wire protocol.

Yeah, you are exactly right and this was my problem.  The remote side of the connection was designed to wait for EOF and it is not possible to generate one with erlang:ports as you pointed out.  It appeared to me that I wasn't even getting any data, but I think I was all along so it was a red-herring to be looking at the transmission itself.  Once I realized the problem was w.r.t. communicating the packet length, the program started working.

> May be
> you have to make some wrapper around your port program.

Yep, exactly.  Thanks so much for the help,  Appreciated.

-Greg

-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 203 bytes
Desc: This is a digitally signed message part
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20101022/d4660030/attachment.bin>


More information about the erlang-questions mailing list