erlang与c通信全过程

1.erlang与c通信的原理

  erlang与c或者其它语言通信方式:首先建立一个中介者(port),他们分别与中介者通信然后中介者为他们传递消息;

  实现的方式有两种:一种是c程序建立进程独立执行,一种是C程序与erlang不独立,以动态库的形式被加载(效率高,程序容易崩溃)

 通信媒介:二进制流.

2.erlang与c通信的方法

 通信的方法:

1)外部程序独立

    port由erlang创建,erlang->c 外部地址是c程序的pid,c->erlang地址是port;

   如果通信?最简单的是该语句:模块名:函数(参数)能够调用到c程序里面的函数。   如何调用的?调用的时候通信的话协议怎么设计?随便设计肯定会存在问题,格式不匹配取得的值会出错。

  步骤:

  1.编写C函数;

  2.协议设计;如调用 c中的add(a,b),erlang发送的字节为:(0,3,2,10,23)四个字节,0,3为真实数据有3个字节,2为函数顺序得由接口来解析,实现对应的调用,后面两个分别为参数。

 那么,erlang程序如何调用呢?分三个步骤:1.注册port并启动监听进程;2.erlang中实现add函数(与port通信);3.进程完成port信号的接收并把add函数的信号发给c的接口(驱动)函数 。

   (1)实现监听进程

 对应的erlang模块需要以进程的形式运行,然后接收到请求就进行类似

{call,Caller,Msg}->

       Port ! {self(),{command,encode(Msg)(编码然后好让接口C函数调用)}},

%接收结果

receive

       {Port,{data,Data}}->

       Caller ! {example1,decode{Data](对data进行解码)}

       end.

     的操作

   (2)erlang中add函数

     add(x,y)->callport({add,x,y})->example1(port启动进程注册好的) ! {call,self(),Msg},-->接收结果 receive {example1,Result}->Result end

 注:port之前得先注册和打开,

  3.编写接口(用于读取,编码,解析,发送C程序的结果),以进程的形式运行;

  4.编写erlang程序用于调用C函数,并与接口通信。


2)外部程序不独立(不推荐,暂时不写)


3.erlang与c通信的具体实现

1)外部程序独立

 文件个数:

 1.c函数.c

实现int add(int x, int y){return x+y;}

 2.基本通信函数(按协议读取,编码,解析).c

//读

      

int read_cmd(byte *buf)
{
  int len;

  if (read_exact(buf, 2) != 2)
    return(-1);
  len = (buf[0] << 8) | buf[1];
  return read_exact(buf, len);
}

int read_exact(byte *buf, int len)
{
  int i, got=0;

  do {
    if ((i = read(0, buf+got, len-got)) <= 0)
      return(i);
    got += i;
  } while (got<len);

  return(len);
}

       //写

int write_cmd(byte *buf, int len)
{
  byte li;

  li = (len >> 8) & 0xff;
  write_exact(&li, 1);
  
  li = len & 0xff;
  write_exact(&li, 1);

  return write_exact(buf, len);
}
int write_exact(byte *buf, int len)
{
  int i, wrote = 0;

  do {
    if ((i = write(1, buf+wrote, len-wrote)) <= 0)
      return (i);
    wrote += i;
  } while (wrote<len);

  return (len);
}


 3.接口(驱动程序,进程).c

 

int main() {
  int fn, arg1, arg2, result;
  byte buff[100];

  while (read_cmd(buff) > 0) {
    fn = buff[0];
    
    if (fn == 1) {
      arg1 = buff[1];
      result = twice(arg1);
    } else if (fn == 2) {
      arg1 = buff[1];
      arg2 = buff[2];
      /* debug -- you can print to stderr to debug
	 fprintf(stderr,"calling sum %i %i\n",arg1,arg2); */
      result = sum(arg1, arg2);
    }

    buff[0] = result;
    write_cmd(buff, 1);
  }
}


 4.erlang程序.erl

-module(example1).
-export([start/0, stop/0]).
-export([twice/1, sum/2]).

start() ->
    spawn(fun() ->
		  register(example1, self()),%注册端口控制进程(即erlang进程)
		  process_flag(trap_exit, true),%变成系统进程可以监控别的进程的退出
		  Port = open_port({spawn, "./example1"}, [{packet, 2}]),%打开一个端口,使得与example1(即那个接口c进程关联),在头部加两个字节用于表示发送消息的长度
		  loop(Port)
	  end).

stop() ->
    example1 ! stop.

twice(X) -> call_port({twice, X}).
sum(X,Y) -> call_port({sum, X, Y}).

call_port(Msg) ->
    example1 ! {call, self(), Msg},%发送到erlang进程
    receive
	{example1, Result} ->%从erlang进程取结果
	    Result
    end.

loop(Port) ->
    receive
	{call, Caller, Msg} ->%接收到命令行请求,请求都用Caller标记
	    Port ! {self(), {command, encode(Msg)}}, %往接口发数据,command由port进程来处理,encode是对协议编码,即c程序取到的协议字段
	    receive
		{Port, {data, Data}} ->%接收到c函数返回数据
		    Caller ! {example1, decode(Data)}%把返回数据解码后发给erlang进程
	    end,
	    loop(Port);
	stop ->
	    Port ! {self(), close},
	    receive
		{Port, closed} ->
		    exit(normal)
	    end;
	{'EXIT', Port, Reason} ->
	    exit({port_terminated,Reason})
    end.

encode({twice, X}) -> [1, X];  
encode({sum, X, Y}) -> [2, X, Y]. 

decode([Int]) -> Int. 

4.结论

  本文简要介绍了erlang程序与c程序通信,对例子做了个简单的介绍。

  通信的重点是 :erlance进程,port进程,驱动进程
(1) erlance进程:负责注册系统进程,等待用户命令,接收和发送请求到port进程,并把返回结果送给用户
(2)port进程:由erlang负责控制,对用户来说只需要open_port并设置驱动C进程和定义协议就OK
(3)驱动进程:负责读取port接收到的请求,解析,并调用对应的函数(用户自己自定义的函数)


转载请注明出处,未经允许不可用于商业用途


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值