[erlang-questions] erlang port and C executable
Joe Williams
joe@REDACTED
Thu Nov 27 05:05:30 CET 2008
My solution to the problem ended up being fairly similar to the example
on in the Interoperability Tutorial, Section 4 Ports
(http://www.erlang.org/doc/tutorial/part_frame.html) as Robert
suggested. I found that it was much simpler once I "got it", as Edwin
said it's "easier when you know how". :)
Thanks guys.
-Joe
Joe Williams wrote:
> 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