This is an example of how to solve the
First of all communication between Erlang and C must be established by creating the port. The Erlang process which creates a port is said to be the connected process of the port. All communication to and from the port should go via the connected process. If the connected process terminates, so will the port (and the external program, if it is written correctly).
The port is created using the BIF
The process is also set to trap exits which makes it possible to detect if the external program fails.
-module(complex1). -export([start/1, init/1]). start(ExtPrg) -> spawn(?MODULE, init, [ExtPrg]). init(ExtPrg) -> register(complex, self()), process_flag(trap_exit, true), Port = open_port({spawn, ExtPrg}, [{packet, 2}]), loop(Port).
Now it is possible to implement
foo(X) -> call_port({foo, X}). bar(Y) -> call_port({bar, Y}). call_port(Msg) -> complex ! {call, self(), Msg}, receive {complex, Result} -> Result end.
The
loop(Port) -> receive {call, Caller, Msg} -> Port ! {self(), {command, encode(Msg)}}, receive {Port, {data, Data}} -> Caller ! {complex, decode(Data)} end, loop(Port) end.
Assuming that both the arguments and the results from the C functions will be less than 256, a very simple encoding/decoding scheme is employed where
encode({foo, X}) -> [1, X]; encode({bar, Y}) -> [2, Y]. decode([Int]) -> Int.
The resulting Erlang program, including functionality for stopping the port and detecting port failures is shown below.
On the C side, it is necessary to write functions for receiving and sending
data with two byte length indicators from/to Erlang. By default, the C program
should read from standard input (file descriptor 0) and write to standard output
(file descriptor 1). Examples of such functions,
Note that
In the
Note that the C program is in a
1. Compile the C code.
unix> gcc -o extprg complex.c erl_comm.c port.c
2. Start Erlang and compile the Erlang code.
unix> erl Erlang (BEAM) emulator version 4.9.1.2 Eshell V4.9.1.2 (abort with ^G) 1> c(complex1). {ok,complex1}
3. Run the example.
2> complex1:start("extprg"). <0.34.0> 3> complex1:foo(3). 4 4> complex1:bar(5). 10 5> complex1:stop(). stop