`
litaocheng
  • 浏览: 337667 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

CNode指南

阅读更多

好久不发文章,因为工作太忙。这个东西就凑凑数吧。各位见谅。

下一篇可能会介绍port,因为工作中用的比较多.

 

 

CNode用户指南

Author: Mail: Date:
litaocheng
litaocheng@gmail.com
2009.7.8

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 相关API

2.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.

  • 作为client,调用 fd = erl_connect("e1@idril") 连接其他节点
  • 作为server
    1. bind(),并listen一个本地端口
    2. 调用 erl_publish(port); 声明绑定的端口
    3. 调用 fd = erl_accept(listen, &conn); 等待client连接

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 client

complex3:

-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;
}
分享到:
评论
3 楼 gashero 2013-12-26  
程老师真棒!
2 楼 litaocheng 2009-07-27  
mryufeng 写道
可以演示下 c调用erlang, erlang调c


好的下次整理一下哦
1 楼 mryufeng 2009-07-27  
可以演示下 c调用erlang, erlang调c

相关推荐

    Erlang_CNode用户指南

    **Erlang_CNode用户指南** 在IT领域,Erlang是一种面向并发的、函数式编程语言,由瑞典电信设备制造商Ericsson开发,主要用于构建高度可靠、可扩展的分布式系统。CNode是Erlang环境中的一个特殊概念,它是Erlang与...

    Erlang_CNode用户指

    Erlang_CNode用户指南通常会涵盖以下几个核心主题: 1. **安装和配置**:指导用户如何在系统上安装Erlang VM和CNode所需的所有依赖项,包括设置环境变量,确保编译器和链接器正确配置。 2. **创建CNode**:详细...

    cnode uni-app项目 + CNode:Node.js专业中文社区

    【标题】"cnode uni-app项目 + CNode:Node.js专业中文社区" 是一个基于Vue.js框架和uni-app开发的应用程序,旨在为Node.js开发者提供一个专业的中文交流平台。这个项目融合了多种技术特性和功能,如搜索、上拉加载更...

    vuecnode用Vue做的MaterialDesign风格CNode官网

    5. `README.md`:项目介绍和指南。 【Vue组件化开发】 Vue-cnode项目中,开发者将UI拆分为多个独立的组件,每个组件负责一部分功能和展示,如登录、论坛列表、帖子详情等。这种组件化开发方式提高了代码的可复用性...

    微信小程序cnode社区版

    8. **README.md**:可能包含项目的介绍、安装和使用指南,帮助开发者理解和运行项目。 开发微信小程序cnode社区版,需要对以下几个关键技术点有深入理解: - **微信小程序API**:微信提供了丰富的API,包括网络...

    cnode社区版_企业城微信小程序js代码前台前端H5页面源码.rar

    8. README或其他文档:提供项目介绍、安装指南、使用说明等。 综合以上分析,这个源码包对于想要了解或开发微信小程序,尤其是针对企业服务的开发者来说,是一个宝贵的资源。它涵盖了前端开发的各个方面,包括页面...

    CNode-android, CNodejs社区移动客户端原生android版.zip

    7. **Android Material Design**:应用可能采用了Material Design设计指南,提供了统一且富有层次感的UI元素和交互效果。 8. **Repository Pattern**:这是一种设计模式,用于处理数据源的抽象,可以是本地数据库、...

    Cnode:React演示

    您可以在找到本指南的最新版本。目录自动格式化代码更改页面&lt;title&gt; 安装依赖项导入组件代码分割添加样式表后处理CSS 添加CSS预处理器(Sass,Less等) 添加图像,字体和文件使用public文件夹更改HTML 在模块...

    sel4.0.8.pdf

    该手册提供了一个全面的指南,用于理解内核服务与对象、能力空间、消息传递、线程与执行、地址空间、虚拟内存、硬件I/O、系统启动以及API参考等多个方面。 内核服务和对象章节主要介绍了内核提供的功能,包括基于...

    新云管理系统3.0版 Google地图生成器提供了,测试了,好用

    Dim XMLDOM, node, Cnode, Cnode1, msginfo Thisurl = "http://" & Request.ServerVariables("HTTP_HOST") 'Response.Clear 'Response.CharSet = "UTF-8" 'Response.ContentType = "text/xml" Call IndexSiteMap("/...

    精粤b760bios降压负载曲线调整12600kf双烤优化功耗

    压缩包内的“说明.txt”文件很可能是详细的操作指南,指导用户如何下载并应用新的BIOS更新,以及如何在BIOS中进行上述调整。而“EFI”文件夹则包含实际的BIOS更新文件,通常需要通过主板的UEFI BIOS升级工具来安装。...

Global site tag (gtag.js) - Google Analytics