#include typedef unsigned char byte;
typedef char int8;
int8 read_exact(byte* buf, int8 len);
int8 write_exact(byte* buf, int8 len);
int main() {
FILE * fp;
fp = fopen("ports.log", "w");
fprintf(fp, "start...\n");
fflush(fp);
byte buf[256]={0};
while(read_exact(buf, 1)==1)
{
int8 len = buf[0];
if(read_exact(buf, len)<=0) return -1;
fprintf(fp, "buf:[%s],len:[%d]\n", buf, len);
fflush(fp);
if(write_exact(&len, 1)<=0) return -1;
if(write_exact(buf, len)<=0) return -1;
}
fprintf(fp, "end...\n");
fclose(fp);
return 0;
}
int8 read_exact(byte* buf, int8 len)
{
int i, got=0;
do {
if ((i=read(0, buf+got, len-got)) <= 0)
return (i);
got += i;
}while (got < len);
return (len);
}
int8 write_exact(byte* buf, int8 len)
{
int i, wrote=0;
do {
if ((i= write(1, buf+wrote, len-wrote)) <= 0)
return (i);
wrote += i;
}while (wrote < len);
return (len);
}
%%echo.erl
%% echo.erl
-module(echo).
-export([start/0, stop/0, echo/1]).
start() ->
spawn(fun() ->
register(echo, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, "./sun.sh"}, [{packet, 1}]),
loop(Port)
end).
stop() ->
echo ! stop.
echo(Msg) ->
echo ! {call, self(), Msg}, %% Msg必须是一个List
receive
Result -> Result
after 1000 -> io:format("time out~n"), true
end.
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, Msg}}, %% Msg必须是一个List
receive
{Port, {data, Data}} -> %% 返回的Data也是一个List
Caller ! Data
end,
loop(Port);
stop ->
Port ! {self(), close},
receive
{Port, closed} -> exit(normal)
end;
{'EXIT', Port, Reason} ->
io:format("port terminated!~n"),
exit({port_terminated, Reason})
end.
下面是我的测试过程:
^_^[sunny@localhost ~/erl/io]86$ gcc echo.c -o echo
^_^[sunny@localhost ~/erl/io]87$ erl
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]
Eshell V5.7.5 (abort with ^G)
1> c(echo).
{ok,echo}
2> echo:start().
<0.39.0>
3> echo:echo(["I_love_linux"]).
"I_love_linux"
4> echo:stop().
stop
5> halt().
^_^[sunny@localhost ~/erl/io]88$ cat ports.log
start...
buf:[I_love_linux],len:[12]
end...
^_^[sunny@localhost ~/erl/io]89$
由此表明,Erlang和C语言连接成功。
拓展:Erlang和Shell脚本的交互。
相信实现了Erlang和C的交互后,Erlang和shell的交互就是“A piece of cake”。
需要两个文件:ls.sh echo.erl
#ls.sh
#!/bin/bash
ls > sun
exit 0
%%echo.erl
-module(echo).
-export([start/0, stop/0]).
start() ->
spawn(fun() ->
register(echo, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, "./ls.sh"}, [stream]),
loop(Port)
end).
loop(Port) ->
io:format("Execute successfully!The port is~p~n", [Port]).
stop() ->
echo ! stop.
注意:ls.sh必须要有可执行的权限。
^_^[sunny@localhost ~/erl/io1]16$ erl
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]
Eshell V5.7.5 (abort with ^G)
1> c(echo).
{ok,echo}
2> echo:start().
<0.39.0>
Execute successfully!The port is#Port<0.1972>
3> halt().
^_^[sunny@localhost ~/erl/io1]17$ cat sun
echo.beam
echo.erl
ls.sh
sun
^_^[sunny@localhost ~/erl/io1]18$ ls
echo.beam echo.erl ls.sh sun
^_^[sunny@localhost ~/erl/io1]19$
到此,我们实现虚拟机启动的技术问题,全部攻克了。