锁定老帖子 主题:CNode指南
精华帖 (0) :: 良好帖 (10) :: 新手帖 (0) :: 隐藏帖 (0)
|
||||
---|---|---|---|---|
作者 | 正文 | |||
发表时间:2009-07-27
好久不发文章,因为工作太忙。这个东西就凑凑数吧。各位见谅。 下一篇可能会介绍port,因为工作中用的比较多.
CNode用户指南
1 概述利用Erlang的 erl_interface ,我们可以构建自己的Erlang "Node",我们称为 "CNode ",erl_interface实现了基本的节点连接,以及消息发送接收,以及Erlang Term 的构建解析. 使用CNode,可以完成很多使用port完成的功能,区别是你的应用是一个c程序,而不需要 一个erlang应用. CNode是hidden node,在erlang的 nodes() 结果中,无法看到CNode(可以通过nodes(connected)获取) 2 CNode 相关API2.1 建立连接erl_init(NULL, 0) 首先进行erlang环境的初始化,主要是内存的初始化. 随后进行C node的初始化,假如我们的C node name为short name, 调用 erl_connect_init(1, "secretcookie", 0) 则创建了一个名称为 c1 的C node. 如果要创建一个long name的C node,那么需要调用 erl_connect_xinit("idril", "cnode", "cnode@idril.ericsson.se", &addr, "secretcookie", 0); . C node可以表现为一个client,也可以表现为一个srever.
2.2 发送接收消息通过调用 erl_receive_msg() ,C node可以从Erlang节点接收消息.其通过建立连接时的fd接收消息. 接收的消息被存放在名为ErlMessage的结构中,ErlMessage的type字段表明接收的消息的类型,如 ERL_REG_SEND 表明 Erlang节点向C node中的某个registered process发送消息.ErlMessage的类型为ETerm的msg字段保存具体 的消息内容. erl_receive_msg 可能会返回 ERL_ERROR (错误发生), ERR_TICK (节点心跳检测),还有和process link/unlink,以及 exit信号相关的返回值,需要我们注意. 代码片段如下: while (loop) { got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); if (got == ERL_TICK) { /* ignore */ } else if (got == ERL_ERROR) { loop = 0; /* exit while loop */ } else { if (emsg.type == ERL_REG_SEND) { 消息体为ETerm,可以使用erl_interface中的相关API进行操作.我们的示例中,消息体为 一个三元tuple,第二个元素为发送者的pid,第三个元素为tuple:{Function,Arg}. 计算的结果,通过 erl_send() 回发给调用者: fromp = erl_element(2, emsg.msg); tuplep = erl_element(3, emsg.msg); fnp = erl_element(1, tuplep); argp = erl_element(2, tuplep); if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { res = foo(ERL_INT_VALUE(argp)); } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { res = bar(ERL_INT_VALUE(argp)); } 最后,所有创建ETerm相关内存,需要释放: erl_free_term(emsg.from); erl_free_term(emsg.msg); erl_free_term(fromp); erl_free_term(tuplep); erl_free_term(fnp); erl_free_term(argp); erl_free_term(resp); resp = erl_format("{cnode, ~i}", res); erl_send(fd, fromp, resp); 2.3 Erlang clientcomplex3: -module(complex3). -export([foo/1, bar/1]). foo(X) -> call_cnode({foo, X}). bar(Y) -> call_cnode({bar, Y}). call_cnode(Msg) -> {any, c1@litao} ! {call, self(), Msg}, receive {cnode, Result} -> Result end. 3 编译运行编译C node: $ gcc -o cserver -I/usr/local/lib/erlang/lib/erl_interface-3.6.2/include \ -L/usr/local/lib/erlang/lib/erl_interface-3.6.2/lib \ complex.c cnode_s.c -g -rdynamic -lerl_interface -lei -lnsl -lpthread 启动epmd: epmd -d -d #以debug方式启动 启动cserver: ./cserver 2342 至此C node启动完成,其绑定的本地端口为2342 启动client: erl -sname t1 设置 c1@litao 的cookie,连接c1节点: (t1@litao)6> erlang:set_cookie('c1@litao', 'secretcookie'). true (t1@litao)7> net_kernel:connect_node('c1@litao'). true (t1@litao)8> nodes(connected). [c1@litao] 执行调用: (t1@litao)12> complex3:foo(3). 4 4 完整代码cnode_s.c: /* cnode_s.c */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include "erl_interface.h" #include "ei.h" #define BUFSIZE 1000 int main(int argc, char **argv) { int port; /* Listen port number */ int listen; /* Listen socket */ int fd; /* fd to Erlang node */ ErlConnect conn; /* Connection data */ int loop = 1; /* Loop flag */ int got; /* Result of receive */ unsigned char buf[BUFSIZE]; /* Buffer for incoming message */ ErlMessage emsg; /* Incoming message */ ETERM *fromp, *tuplep, *fnp, *argp, *resp; int res; port = atoi(argv[1]); erl_init(NULL, 0); if (erl_connect_init(1, "secretcookie", 0) == -1) erl_err_quit("erl_connect_init"); /* Make a listen socket */ if ((listen = my_listen(port)) <= 0) erl_err_quit("my_listen"); if (erl_publish(port) == -1) erl_err_quit("erl_publish"); if ((fd = erl_accept(listen, &conn)) == ERL_ERROR) erl_err_quit("erl_accept"); fprintf(stderr, "Connected to %s\n\r", conn.nodename); while (loop) { got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); if (got == ERL_TICK) { /* ignore */ } else if (got == ERL_ERROR) { loop = 0; } else { if (emsg.type == ERL_REG_SEND) { fromp = erl_element(2, emsg.msg); tuplep = erl_element(3, emsg.msg); fnp = erl_element(1, tuplep); argp = erl_element(2, tuplep); if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { res = foo(ERL_INT_VALUE(argp)); } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { res = bar(ERL_INT_VALUE(argp)); } resp = erl_format("{cnode, ~i}", res); erl_send(fd, fromp, resp); erl_free_term(emsg.from); erl_free_term(emsg.msg); erl_free_term(fromp); erl_free_term(tuplep); erl_free_term(fnp); erl_free_term(argp); erl_free_term(resp); } } } /* while */ } int my_listen(int port) { int listen_fd; struct sockaddr_in addr; int on = 1; if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return (-1); setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); memset((void*) &addr, 0, (size_t) sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) return (-1); listen(listen_fd, 5); return listen_fd; } compex.c: /* complex.c */ int foo(int x) { return x+1; } int bar(int y) { return y*2; } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
||||
返回顶楼 | ||||
发表时间:2009-07-27
可以演示下 c调用erlang, erlang调c
|
||||
返回顶楼 | ||||
发表时间:2009-07-27
mryufeng 写道 可以演示下 c调用erlang, erlang调c 好的下次整理一下哦 |
||||
返回顶楼 | ||||
浏览 3652 次