title: 實現Golang和Erlang的鏈接(Port)html
在Erlang中,有不少種方式去實現與其餘語言的交互,常見的幾種方式有golang
後面幾種難度都是有的,也使用了比較複雜的C/C++,並且比較容易出現問題。TCP的方式是經過網絡協議,我的也不是很喜歡,那就剩下Port方式去鏈接Erlang服務器。shell
在Erlang中使用Port很是簡單,實際上就是經過標準輸入輸出流與外部程序就行交互。服務器
如今我仍是沿用官方文檔中代碼,僅作部分修改,實現Erlang與Golang的交互。網絡
%% complex1.erl -module(complex1). -export([start/1, stop/0, init/1]). -export([foo/1, bar/1]). start(ExtPrg) -> spawn(?MODULE, init, [ExtPrg]). stop() -> complex ! stop. foo(X) -> call_port({foo, X}). bar(Y) -> call_port({bar, Y}). call_port(Msg) -> complex ! {call, self(), Msg}, receive {complex, Result} -> Result end. init(ExtPrg) -> register(complex, self()), process_flag(trap_exit, true), %% 注意{packet, 2}表明的是用2個字節表示傳輸的 %% Port = open_port({spawn, ExtPrg}, [{packet, 2}]), %% 在這裏不去處理這個數據頭,不須要這個參數 Port = open_port({spawn, ExtPrg}, []), loop(Port). loop(Port) -> receive {call, Caller, Msg} -> Port ! {self(), {command, encode(Msg)}}, receive {Port, {data, Data}} -> Caller ! {complex, decode(Data)} end, loop(Port); stop -> Port ! {self(), close}, receive {Port, closed} -> exit(normal) end; {'EXIT', Port, Reason} -> exit(port_terminated) end. %% 進行編碼,將數據轉成2進制 encode({foo, X}) -> <<1:8, X:8>>; encode({bar, Y}) -> <<2:8, Y:8>>]. %% 這裏有點特別, decode(Data) -> erlang:list_to_binary(Data).
對於Golang,須要讀取標準輸入流的數據,這裏我用bufio處理下(其實也沒有太多必要,哈哈哈)。由於這裏沒有使用數據流的頭部來記錄數據的長度,因此默認將數據長度設置爲2的byte數組。oop
// port.go package main import ( "bufio" "os" ) func main() { reader := bufio.NewReader(os.Stdin) writer := bufio.NewWriter(os.Stdout) for { buff := make([]byte, 2) _, err := reader.Read(buff) if err != nil { panic(err.Error()) } switch int(buff[0]) { case 1: buff[1] = byte(foo(int(buff[1]))) case 2: buff[1] = byte(bar(int(buff[1]))) } writer.Write(buff[1:2]) // 這裏須要注意,要用Flush進行處理,不然erlang端收不到信息 writer.Flush() } } func foo(num int) int { return num + 1 } func bar(num int) int { return 2 * num }
go build port.go
unix> erl Erlang (BEAM) emulator version 4.9.1.2 Eshell V4.9.1.2 (abort with ^G) 1> c(complex1). {ok,complex1}
2> complex1:start("extprg"). <0.34.0> 3> complex1:foo(3). 4 4> complex1:bar(5). 10 5> complex1:stop(). stop