[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