[erlang-questions] erlang port and C executable

Joe Williams joe@REDACTED
Sun Nov 23 07:21:23 CET 2008


Edwin/Robert,

Thanks for the info, I will see what I can put together and if it's 
worthwhile report back my findings.

-Joe


Edwin Fine wrote:
> 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 <joe@REDACTED 
> <mailto:joe@REDACTED>> 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: joe@REDACTED <mailto:joe@REDACTED>
>
>     _______________________________________________
>     erlang-questions mailing list
>     erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
>     http://www.erlang.org/mailman/listinfo/erlang-questions
>
>

-- 
Name: Joseph A. Williams
Email: joe@REDACTED




More information about the erlang-questions mailing list