[erlang-questions] erlang port and C executable

Edwin Fine <>
Sun Nov 23 07:14:56 CET 2008


Joe,

I don't know if this is still a problem, but I didn't know the answer, so I
was intrigued. Having never used C ports before, I thought it would be
useful to learn about them.

I looked at the C code for Erlang (io.c module) and it seems that this
signal (badsig) is sent when bad port command is received. The port command
was bad because you can't just send raw data to a port as in Port !
<<"Hello">>. It requires a specific format. You have to either send Port !
{self(), {command, <<"Hello">>}} or (which I like better)
erlang:port_command(Port, <<"Hello">>).

In terms of how you can send and receive strings, this whole port thing
turned out to be much more difficult to figure than I anticipated (but
easier when you know how). One of the most annoying aspects is that under
circumstances that are not clear to me, the C program that is spawned
sometimes does not seem to be sent a signal for end of file when you close
the port, so if it is reading stdin, it's just going to sit there until
killed manually. Worse, if it gets stuck doing something and is NOT reading
stdin then you are out of luck.

But what if the 'C' program is not under your control, say, it's part of
Linux, and you need to make sure it's killed when you are done? Then I
believe you need to write a wrapper around the 'C' program. I refer you to
the following post for an interesting way to do this:

http://www.erlang.org/pipermail/erlang-questions/2007-October/030377.html

As for how to send and receive strings, assuming there is a way to terminate
the 'C' program, I eventually came up with the following "demo" code (which
does rely on newlines, and I know there are other ways; this is one of
them). Hope this helps.

Regards,
Edwin Fine

/* echo_svr.c: Simple C program to echo stdin to stdout */
#include <stdio.h>

int main()
{
    char buf[4096];

    while (fgets(buf, sizeof(buf), stdin) != NULL)
    {
        fputs(buf, stdout);
        fflush(stdout);
    }

    return 0;
}

echo_svr.erl:

-module(test_echo_svr).
-export([go/2]).

go(EchoSvrExecFilePath, Iters) when is_list(EchoSvrExecFilePath),
is_integer(Iters), Iters >= 0  ->
    process_flag(trap_exit, true),
    Port = erlang:open_port({spawn, EchoSvrExecFilePath}, [binary]),
    test(Port, <<>>, Iters, 1).

test(Port, _Buf, 0, _N) ->
    erlang:port_close(Port), ok;
test(Port, Buf, Iters, N) ->
    Out = list_to_binary([<<"Test message ">>, integer_to_list(N), $\n]),
    erlang:port_command(Port, Out),
    receive
        {Port, {data, In}} ->
            {Line, Rest} = parse(list_to_binary([Buf, In])),
            io:format("~p~n", [Line]),
            test(Port, Rest, Iters - 1, N + 1)
    after 3000 ->
            io:format("Receive timeout, stopping.~n")
    end.

parse(Msg) -> parse(Msg, []).

parse(<<>>, Acc) ->                  {lists:reverse(Acc), <<>>};
parse(<<$\n, Rest/binary>>, Acc)  -> {lists:reverse(Acc), Rest}; % EOL
parse(<<Byte, Rest/binary>>, Acc) ->  parse(Rest, [Byte|Acc]).

113> test_echo_svr:go("/path/to/echo_svr", 3).
"Test message 1"
"Test message 2"
"Test message 3"
ok


On Fri, Nov 21, 2008 at 6:37 PM, Joe Williams <> wrote:

> Hello,
>
> I am having an issue when I attempt to send and receive messages to a C
> executable. I believe the task should be fairly trivial but I am getting
> hung up on sending messages to the port. Here's what I have so far:
>
> > Eshell V5.6.3  (abort with ^G)
> > 1> Cmd = "SOME_EXECUTABLE",
> > 1> Port = open_port({spawn, Cmd}, []).
> > #Port<0.93>
> > 2> receive
> > 2> {Port, {data, Data}} ->
> > 2> io:format("~p~n", [Data]);
> > 2> Error ->
> > 2> io:format("~p~n", [Error])
> > 2> end.
> > "TEXT FROM THE EXECUTABLE"
> > ok
> > 3> Port ! <<"TEXT TO THE EXECUTABLE">>.
> > ** exception exit: badsig
> > 4> Port ! <<"TEXT TO THE EXECUTABLE">>.
> > <<"TEXT TO THE EXECUTABLE">>
> > 5> receive
> > 5> {Port, {data, Data}} ->
> > 5> io:format("~p~n", [Data]);
> > 5> Error ->
> > 5> io:format("~p~n", [Error])
> > 5> end.
>
> After the last end my code just hangs and waits to receive a message
> rather than receiving the response from "TEXT TO THE EXECUTABLE". Since
> it received the first message properly I assume it would receive further
> responses in the same way. So I have two questions, the first is what
> does "exception exit: badsig" generally mean? The second how can I write
> this in such a way that I can send and receive strings until I have the
> program exit?
>
> Any guidance is appreciated.
>
> -Joe
>
> --
> Name: Joseph A. Williams
> Email: 
>
> _______________________________________________
> erlang-questions mailing list
> 
> http://www.erlang.org/mailman/listinfo/erlang-questions
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20081123/2299fc39/attachment.html>


More information about the erlang-questions mailing list