【Erlang新手成长日记】Erlang端口与外部C程序交互

参考文档:

  《Programming Erlang》,第12章:Interfacing Techniques

创建C源文件:

  hello.c  具体函数的实现

hello.c
int twice(int arg) {
    return (arg * arg);
}

int sum(int arg1, int arg2) {
    return (arg1 + arg2);
}

  hello_driver.c  驱动程序运行

hello_driver.c
#include <stdio.h>

#define BUFFER_SIZE 100

typedef unsigned char byte; //8 bit

int read_cmd(byte *buffer);
int write_cmd(byte *buffer, int length);

int main() {
    int function_number; //函数号
    int arg1, arg2; //参数
    int result; //结果
    byte buffer[BUFFER_SIZE]; //缓冲区
    
    while(read_cmd(buffer) > 0) {
        function_number = buffer[0];
        switch(function_number) {
            case 1:
                //执行函数 twice
                arg1 = buffer[1];
                result = twice(arg1);
                break;
            case 2:
                //执行函数 sum
                arg1 = buffer[1];
                arg2 = buffer[2];
                result = sum(arg1, arg2);
                break;
            default:
                // error
                break;
        }
        buffer[0] = result;
        write_cmd(buffer, 1);
    }
    
    return 0;
}

  erl_communication.c  与Erlang程序交互

erl_communication.c
 1 #include <unistd.h>
 2 
 3 typedef unsigned char byte;
 4 
 5 int read_cmd(byte *buffer);
 6 int write_cmd(byte *buffer, int length);
 7 int read_exact(byte *buffer, int length);
 8 int read_exact(byte *buffer, int length);
 9 
10 int read_cmd(byte *buffer) {
11     int length; //int 长度 16 bit
12     
13     if(read_exact(buffer, 2) != 2) {
14         return -1;
15     }
16     length = (buffer[0] << 8) | buffer[1];
17     
18     return read_exact(buffer, length);
19 }
20 
21 int write_cmd(byte *buffer, int length) {
22     byte li; //unsigned char 长度 8 bit
23     
24     li = (length >> 8) & 0xff;
25     write_exact(&li, 1);
26     li = length & 0xff;
27     write_exact(&li, 1);
28     
29     return write_exact(buffer, length);
30 }
31 
32 int read_exact(byte *buffer, int length) {
33     int i, got = 0;
34     
35     do {
36         /*
37          * read函数定义:ssize_t read(int fildes, void *buf, size_t nbyte);
38          * read函数描述:The read() function attempts to read nbyte bytes from the file associated with the open file descriptor, fildes, into the buffer pointed to by buf.
39          * 备注:fildes值0,标准输入
40          */
41         if((i = read(0, (buffer + got), (length - got))) <= 0) {
42             return i;
43         }
44         got += i;
45     } while(got < length);
46     
47     return length;
48 }
49 
50 int write_exact(byte *buffer, int length) {
51     int i, wrote = 0;
52     
53     do {
54         /*
55          * write函数定义:ssize_t write(int fildes, const void *buf, size_t nbyte);
56          * write函数描述:The write() function attempts to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes.
57          * 备注:fildes值1,标准输出
58          */
59         if((i = write(1, (buffer + wrote), (length - wrote)))) {
60             return i;
61         }
62         wrote += i;
63     } while(wrote < length);
64     
65     return length;
66 }

创建Erlang源文件

  hello.erl  创建进程,打开与C生成的可执行文件之间的端口,通过消息传递进行交互

  Port = open_port(PortName, PortSettings)

  open_port/2:http://www.erlang.org/doc/man/erlang.html#open_port-2  

  This returns a port. The following messages can be sent to a port: 

  Port ! {PidC, {command, Data}}  

    Send Data (an IO List) to the port.

  Port !{PidC, {connect, Pid1}}

    Change the PID of the connected process from PidC to Pid1.

  Port ! {PidC, close}

    Close the port.

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

编译C源文件,生成可执行文件

gcc -o hello hello.c hello_driver.c erl_communication.c

编译Erlang源文件,生成.beam文件

erlc hello.erl

转载于:https://www.cnblogs.com/dyingbleed/archive/2012/09/01/2666698.html

猜你喜欢

转载自blog.csdn.net/weixin_33873846/article/details/93446940
今日推荐