英文:
Converting Erlang-C port example to Erlang-Golang
问题
我正在尝试为Erlang编写一个Golang驱动程序,通过Erlang端口进行访问。
我已经从Erlang C端口示例开始,它可以正常工作:
http://www.erlang.org/doc/tutorial/c_port.html
现在我正在尝试将C代码移植到Golang;只是尝试回显一个简单的“Hello World\n”消息,使用“\n”作为分隔符。
所以我的Golang代码如下:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
bytes, _ := reader.ReadBytes('\n')
os.Stdout.Write(bytes)
}
我可以编译并从命令行运行它,如下所示:
justin@justin-ThinkPad-X240:~/work/erlang_golang_port$ go build -o tmp/echo echo.go
justin@justin-ThinkPad-X240:~/work/erlang_golang_port$ ./tmp/echo
Enter text: hello
hello
然而,当我尝试从Erlang端调用驱动程序(下面是Erlang代码)时,我得到以下错误:
justin@justin-ThinkPad-X240:~/work/erlang_golang_port$ erl
Erlang R16B03 (erts-5.10.4) [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]
Eshell V5.10.4 (abort with ^G)
1> c(complex1).
{ok,complex1}
2> complex1:start("./tmp/echo").
<0.41.0>
3> complex1:ping().
=ERROR REPORT==== 23-Apr-2015::08:56:47 ===
Bad value on output port './tmp/echo'
我感觉消息已经成功传递给驱动程序,但我以某种方式错误地返回了响应。
谢谢。
英文:
I'm trying to write a Golang driver for Erlang, accesible via an Erlang port.
I've started with the Erlang C port example, which works fine:
http://www.erlang.org/doc/tutorial/c_port.html
Now I'm trying to port the C code to Golang; just trying to echo a simple 'Hello World\n' message, using '\n' as the delimiter.
So my Golang code is as follows:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
bytes, _ := reader.ReadBytes('\n')
os.Stdout.Write(bytes)
}
And I can compile it and run it from the command line as follows:
justin@justin-ThinkPad-X240:~/work/erlang_golang_port$ go build -o tmp/echo echo.go
justin@justin-ThinkPad-X240:~/work/erlang_golang_port$ ./tmp/echo
Enter text: hello
hello
However when I try to call the driver from the Erlang side (Erlang code below) I get the following:
justin@justin-ThinkPad-X240:~/work/erlang_golang_port$ erl
Erlang R16B03 (erts-5.10.4) [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]
Eshell V5.10.4 (abort with ^G)
1> c(complex1).
{ok,complex1}
2> complex1:start("./tmp/echo").
<0.41.0>
3> complex1:ping().
=ERROR REPORT==== 23-Apr-2015::08:56:47 ===
Bad value on output port './tmp/echo'
I have the sense that the message is being passed OK to the driver, but that I am somehow returning the response incorrectly.
TIA.
Erlang port code:
-module(complex1).
-export([start/1, stop/0, init/1]).
-export([ping/0]).
-define(HELLO_WORLD, [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 46]).
start(ExtPrg) ->
spawn(?MODULE, init, [ExtPrg]).
stop() ->
complex ! stop.
ping() ->
call_port({ping, ?HELLO_WORLD++[10]}).
call_port(Msg) ->
complex ! {call, self(), Msg},
receive
{complex, Result} ->
Result
end.
init(ExtPrg) ->
register(complex, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
loop(Port).
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, Msg}},
receive
{Port, {data, Data}} ->
Caller ! {complex, Data}
end,
loop(Port);
stop ->
Port ! {self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, _Reason} ->
exit(port_terminated)
end.
答案1
得分: 6
echo.go
:
package main
import (
"bufio"
"os"
)
func main() {
for {
reader := bufio.NewReader(os.Stdin)
bytes, _ := reader.ReadBytes('\n')
os.Stdout.Write(bytes)
}
}
complex1.erl
:
-module(complex1).
-export([start/1, stop/0, init/1]).
-export([send/1]).
start(ExtPrg) ->
spawn_link(?MODULE, init, [ExtPrg]).
stop() ->
complex ! stop.
send(Y) -> call_port({msg, Y}).
call_port({msg, Msg}) ->
complex ! {call, self(), Msg},
receive
{complex, Result} ->
Result
end.
init(ExtPrg) ->
register(complex, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, ExtPrg}, []),
loop(Port).
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, Msg++[10]}},
Data = receive_all(Port, 100),
Caller ! {complex, Data},
loop(Port);
stop ->
Port ! {self(), close},
receive {Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
exit({port_terminated, Reason})
end.
receive_all(Port, Timeout) -> receive_all(Port, Timeout, []).
receive_all(Port, Timeout, Buffer) ->
receive
{Port, {data, Data}} ->
receive_all(Port, Timeout, [Data | Buffer])
after Timeout ->
lists:flatten(lists:reverse(Buffer))
end.
$ erl
Erlang R16B02_basho8 (erts-5.10.3) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V5.10.3 (abort with ^G)
1> c(complex1).
{ok,complex1}
2> complex1:start("go run echo.go").
<0.40.0>
3> complex1:send("asdhadlsjahdslahjdlhd").
"asdhadlsjahdslahjdlhd"
4> complex1:send("aksdghjakdsgalkdgaldsagdlkagdlkadg").
"aksdghjakdsgalkdgaldsagdlkagdlkadg"
英文:
Posting this answer based on @Justin's follow-up question here, which contains a slightly different but working answer.
echo.go
:
package main
import (
"bufio"
"os"
)
func main() {
for{
reader := bufio.NewReader(os.Stdin)
bytes, _ := reader.ReadBytes('\n')
os.Stdout.Write(bytes)
}
}
complex1.erl
:
-module(complex1).
-export([start/1, stop/0, init/1]).
-export([send/1]).
start(ExtPrg) ->
spawn_link(?MODULE, init, [ExtPrg]).
stop() ->
complex ! stop.
send(Y) -> call_port({msg, Y}).
call_port({msg, Msg}) ->
complex ! {call, self(), Msg},
receive
{complex, Result} ->
Result
end.
init(ExtPrg) ->
register(complex, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, ExtPrg}, []),
loop(Port).
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, Msg++[10]}},
Data = receive_all(Port, 100),
Caller ! {complex, Data},
loop(Port);
stop ->
Port ! {self(), close},
receive {Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
exit({port_terminated, Reason})
end.
receive_all(Port, Timeout) -> receive_all(Port, Timeout, []).
receive_all(Port, Timeout, Buffer) ->
receive
{Port, {data, Data}} ->
receive_all(Port, Timeout, [Data | Buffer])
after Timeout ->
lists:flatten(lists:reverse(Buffer))
end.
$ erl
Erlang R16B02_basho8 (erts-5.10.3) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V5.10.3 (abort with ^G)
1> c(complex1).
{ok,complex1}
2> complex1:start("go run echo.go").
<0.40.0>
3> complex1:send("asdhadlsjahdslahjdlhd").
"asdhadlsjahdslahjdlhd"
4> complex1:send("aksdghjakdsgalkdgaldsagdlkagdlkadg").
"aksdghjakdsgalkdgaldsagdlkagdlkadg"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论