Erlang 与 c 函数 对接

来源:互联网 发布:淘宝详情页是什么 编辑:程序博客网 时间:2024/05/01 04:19

    一种编程语言同其他的语言结合互操作,充分利用现有资源,是很常见的事情. 也有特定的编程语言很擅长同其他语言的结合,如LUA.  在Erlang中也有很多方法同其他的编程语言结合.如通过内链驱动,原生实现函数(NIF)等.


    Erlang虚拟机中通过一种端口的对象概念同外部程序进行通信,外部程序在端口处取得数据进行处理,处理完成后再送回端口,Erlang虚拟机创建端口的进程会将请求数据发到端口,再等待收回结果.所以说这需要一个协议,有了协议不同的语言间就可以交互了. 


    下面有两个非常简单的c语言函数,准备再erlang中调用:

example1.c

  1 int sum(int x,int y){                                                         2   3     return x + y;  4 }  5   6 int twice(int x){  7   8     return x*2;  9 }

     定义的规则如下:

    1. sum(x,y) 的调用会被编译成字节序列 [1, x, y]

    2. twice(x) 的调用会被编译成字节序列[2, x]

    3. 所有的数据包都带有两个字节的长度头

    4. 返回值,参数都是一个字节长度

    有了上述的这几条约定,就应该可以完成简单的函数的调用了.接下来就是双方都按这些规则交换数据就可以了,也就是所谓的driver程序了.

 example1_driver.c

<span style="font-size:14px;">  1 #include <stdio.h>                                                                                               2 #include <stdlib.h>  3   4 typedef unsigned char byte;  5   6 int main(){  7       8     int function = 0;  9     int arg1 = 0; 10     int arg2 = 0; 11     int result = 0; 12     byte buf[100] = {0}; 13  14     while(read_cmd(buf) > 0){ 15          16         function = buf[0]; 17          18         if(function == 1){ 19              arg1 = buf[1]; 20              arg2 = buf[2]; 21              result = sum(arg1,arg2); 22         } else if(function == 2){ 23              arg1 = buf[1]; 24              result = twice(arg1); 25         }else{ 26              exit(0);            27         } 28  29          30         buf[0] = result; 31         write_cmd(buf,1); 32     } 33 } </span>
上面是C语言端的实现逻辑,它会不断的从标准输入取得计算的数据,计算之后在输出到标准输出中,这里所谓的标准输入输出,也就是Erlang的port. Erlang的端口进程会负责启动这个C程序,同时对它进行管理,Erlang端口进程不在了,也会杀掉这个C程序, 当这个C程序意外的挂掉之后,Erlang也会负责重新启动它. 这里面还涉及到两个实现的具体函数,不会影响整个逻辑. 贴出来如下:

<span style="font-size:14px;">  1 #include <unistd.h>                                                                                              2   3 typedef unsigned char byte;  4   5 int read_cmd(byte *buf)  6 {  7     int len;  8   9     if(read_exact(buf,2) != 2) 10         return -1; 11  12     len = (buf[0] << 8 | buf[1]); 13  14     return read_exact(buf,len); 15 } 16  17 int write_cmd(byte *buf,int len) 18 { 19     byte li; 20  21     li = (len >> 8) & 0xff; 22     write_exact(&li,1); 23     li = len & 0xff; 24     write_exact(&li,1); 25  26     return write_exact(buf,len); 27 } 28  29 int read_exact(byte *buf,int len){ 30     int i = 0; 31     int got = 0; 32  33     do { 34         if((i = read(0,buf + got, len-got)) <= 0) 35                 return i; 36         got = got + i; 37     }while(got < len); 38  39     return len; 40 } 41  42 int write_exact(byte *buf,int len){ 43     int i = 0; 44     int wrote = 0; 45  46     do{ 47         if((i = write(1,buf + wrote,len - wrote)) <= 0) 48            return i; 49         wrote = wrote + i; 50     }while(wrote < len); 51  52     return len; 53 } </span><span style="font-size:18px;">     </span>

Erlang 这边同样是按照规则实现函数调用:

    example1.erl

<span style="font-size:14px;">  1 -module(example1).                                                                                               2   3 -export([start/0,stop/0]).  4 -export([twice/1,sum/2]).  5   6 start() ->  7         register(example1,spawn(  8                             fun() ->  9                                 process_flag(trap_exit,true), 10                                 Port = open_port({spawn,"./example1"},[{packet,2}]), 11                                 loop(Port) 12                             end)). 13  14  15 stop() -> 16         ?MODULE ! stop. 17  18 twice(X) -> call_port({twice,X}). 19 sum(X,Y) -> call_port({sum,X,Y}). 20  21 call_port(Msg) -> 22         ?MODULE ! {call, self(), Msg}, 23         receive 24                 {?MODULE,Result} -> 25                         Result 26         end. 27  28 loop(Port) -> 29         receive 30                 {call, Caller, Msg} -> 31                         Port ! {self(),{command,encode(Msg)}}, 32                         receive 33                                 {Port,{data,Data}} -> 34                                         Caller ! {?MODULE,decode(Data)} 35                         end, 36                         loop(Port); 37                 stop -> 38                         Port ! {self(),close}, 39                         receive 40                                 {Port,closed} -> 41                                         exit(normal) 42                         end; 43                 {'EXIT',Port,Reason} -> 44                         exit({port_terminated,Reason}) 45         end. 46  47 encode({sum,X,Y}) -> [1,X,Y]; 48 encode({twice,X}) -> [2,X]. 49  50 decode([Int]) -> Int.</span>


下面的问题就是编译,试一试了:

   erlc example1.erl

   gcc -o example1 example1.c example_driver.c erl_comm.c


    example1:start().

    example:sum(23,43).

    example:twice(10).















0 0
原创粉丝点击