实现Golang和Erlang的连接(Port)

栏目: Erlang · 发布时间: 7年前

内容简介:在Erlang中,有很多种方式去实现与其他语言的交互,常见的几种方式有后面几种难度都是有的,也使用了比较复杂的C/C++,而且比较容易出现问题。TCP的方式是通过网络协议,个人也不是很喜欢,那就剩下Port方式去连接Erlang服务器。

title: 实现Golang和Erlang的连接(Port) categories: Golang

在Erlang中,有很多种方式去实现与其他语言的交互,常见的几种方式有

  1. 使用TCP协议交互
  2. 使用Port
  3. 使用Erl_Interface方式去实现
  4. CNode
  5. NIF

后面几种难度都是有的,也使用了比较复杂的C/C++,而且比较容易出现问题。TCP的方式是通过网络协议,个人也不是很喜欢,那就剩下Port方式去连接Erlang服务器。

Erlang的官方文档中对Port的介绍

在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数组。

// 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
}

使用

步骤1 编译port.go

go build port.go

步骤2 运行Erlang虚拟机

unix> erl
Erlang (BEAM) emulator version 4.9.1.2

Eshell V4.9.1.2 (abort with ^G)
1> c(complex1).
{ok,complex1}

步骤3 运行

2> complex1:start("extprg").
<0.34.0>
3> complex1:foo(3).
4
4> complex1:bar(5).
10
5> complex1:stop().
stop

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Mobilizing Web Sites

Mobilizing Web Sites

Layon, Kristofer / 2011-12 / 266.00元

Everyone has been talking about the mobile web in recent years, and more of us are browsing the web on smartphones and similar devices than ever before. But most of what we are viewing has not yet bee......一起来看看 《Mobilizing Web Sites》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具