将Erlang-C端口示例转换为Erlang-Golang

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 ' message, using ' ' 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('
')
    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.
dongyi8416
dongyi8416 跟进工作示例:stackoverflow.com/questions/32200352/…
4 年多之前 回复
doudao1922
doudao1922 您可以将工作代码发布为答案并将其标记为答案吗?将来可能对其他人有帮助。
接近 5 年之前 回复
dougou2937
dougou2937 请将此问题标记为已回答。
5 年多之前 回复
dongmiao4733
dongmiao4733 应该已经发现了;错误地调换了C示例。作品。谢谢。
5 年多之前 回复
dounuogong0358
dounuogong0358fmt.Print(“Entertext:”)`写入标准输出。在erlang过程中,书面文本是意外的。
5 年多之前 回复
doushizhou4477
doushizhou4477 ping/0使用call_port/1将元组作为消息发送到端口进程,然后将其发送到端口。发送到端口的实际数据只能是字节列表。
5 年多之前 回复

1个回答

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('
')
        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"
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐