[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