在开始调用 Erl_interface
函数之前,内存处理需要初始化:
erl_init(NULL,0);
现在C结点已经初始化了。如果使用了短结点名,则使用 erl_connect_init()
erl_connect_init(1,"secretcookie",0);
第一个参数是整数用于构造结点名。这个例子中纯结点名是"c1"。第二个参数是字符串描述的magic cookie,用于识别结点所在的群组。第三个参数是整数,用于标识一个C node的实例。
如果使用长结点名,初始化是如下调用:
erl_connect_xinit("idril","cnode","cnode@idril.ericsson.se",&addr,"secretcookie",0);
前面的3个参数是主机名、纯结点名和完整结点名。第四个参数是指向 in_addr
结构体的指针,标识主机的IP地址,第五个和第六个参数是magic cookie和实例号。
C node可以作为服务器也可以作为客户端与Erlang-C通信。如果作为客户端,它使用 erl_connect()
连接到一个Erlang结点,然后成功返回打开的文件描述符:
fd=erl_connect("e1@idril");
如果C node作为服务器,他必须首先创建socket(调用bind()和listen())和监听合适的端口。然后发布自己的名字和端口号到 epmd
(erlang端口映射守护进程,查看epmd的手册):
erl_publish(port);
现在C node服务器可以接受Erlang结点的连接了:
fd=erl_accept(listen,&conn);
第二个参数是 ErlConnect
结构体,包含了连接的有用信息;例如Erlang结点名。
C node可以用 erl_receive_msg()
接收消息。这个函数从打开的文件描述符fd读取数据到缓冲区,然后将结果存入 ErlMessage
类型结构体 emsg 。 ErlMessage
结构体拥有一个字段 type 定义了接受到的消息类型。这种情况下 ERL_REG_SEND
标识接受到了注册进程的消息。手机的消息,一个 ETERM
存放在 msg 字段中。
需要注意的是 ERL_ERROR
类型和 ERL_TICK
类型,分别对应错误和存活检查。其他类型大概是link/unlink和exit之类的。
while(loop) {
got=erl_receive_msg(fd,buf,BUFSIZE,&emsg);
if (got=ERL_TICK) { //忽略即可
} else if(got==ERL_ERROR) {
loop=0;
} else {
if (emsg.type==ERL_REG_SEND) {
消息是一个 ETERM
结构体, erl_interface
函数可以用于操作它。这种情况下,消息是一个三元组(与Erlang代码有关,看看上面)。第二个元素是调用者的pid,第三个元素是元组 {Function,Arg}
决定使用何种参数调用哪个函数。函数调用的结果放入 ETERM
结构体,然后用 erl_send()
发送回去,附带上打开的文件描述符、pid和术语作为参数。
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);
最后 ETERM
结构体创建函数(包括 erl_receive_msg()
分配的内存)必须释放掉:
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);
最终的C程序有如下面的样子。第一个C node服务器使用短结点名:
/* 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; //监听端口号
int listen; //监听socket
int fd; //Erlang结点的文件句柄
ErlConnect conn; //连接数据
int loop=1;
int got;
unsigned char buf[BUFSIZE];
ErlMessage emsg;
ETERM *fromp, *tuplep, *fnp, *argp, *resp;
int res;
port=atoi(argv[1]);
erl_init(NULL,0); //初始化c node
if (erl_connect_init(1,"secretcookie",0)==-1)
erl_err_quit("erl_connect_init");
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) {
//忽略
}else if (got==ERL_ERROR) {
loop=0;
}else {
if (emsg.type==ERL_REG_SEND) {
fropm=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);
}
}
}
}
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;
}
下面的例子是长结点名模式的,区别只是在于 erl_connect_xinit()
。
下面的例子是C node客户端:
/* cnode_c.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 fd;
int loop=1;
int got;
unsigned char buf[BUFSIZE];
ErlMessage emsg;
ETERM *fromp, *tuplep, *fnp, *argp, *resp;
int res;
erl_init(NULL,0);
if (erl_connect_init(1,"secretcookie",0)==-1)
erl_err_quit("erl_connect_init");
if ((fd=erl_connect("e1@idril"))<0)
erl_err_quit("erl_connect");
fprintf(stderr,"Connected to ei@idril\n\r");
while(loop) {
got=erl_receive_msg(fd,buf,BUFSIZE,&emsg);
if (got=ERL_TICK) {
//忽略
}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);
}
}
}
}
相关推荐
在Erlang中,节点(Node)是运行Erlang虚拟机(VM,也称为BEAM)的实体,可以是本地进程,也可以是远程机器上的进程。节点之间可以进行通信,这是Erlang分布式计算的基础。现在我们来深入探讨如何进行Erlang节点的...
派尔 PyErl是Python的Erlang接口。...pyerl.mk_string("world")int = pyerl.mk_int(-1)list = pyerl.mk_list([atom, string, int])print list呼叫rpc # just call pingpong:ping() in node2@localh
教育应用程序接口CNErloungeIII周爱民aimingoo约2530PPT概要.pptx主要探讨了如何在不同的编程语言中与Erlang进行交互,特别是通过C语言实现C-Node的方式。Erlang是一种函数式编程语言,以其并发处理和容错能力而闻名...
### 重要知识点解析 ...通过以上分析,我们可以了解到笔试题目中涉及的基本逻辑推理技巧、C/C++编程基础以及Erlang语言的简单应用,这对于准备应聘Erlang开发工程师岗位的人来说是非常有价值的复习资料。
- **erts-10.3**:这是Erlang Run-Time System的一个版本,用于运行EMQ X Broker的Erlang虚拟机。 - **data**:这个目录可能存储持久化的数据,例如MQTT客户端的会话信息和订阅信息。 - **releases**:包含了不同...
Copyright 2014 Chef Software Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License ...
变量值: C:\Program Files\Erlang\R21 ``` - 在系统环境变量 Path 中添加 `%ERLANG_HOME%\bin`。 5. **安装RabbitMQ**: - 直接运行安装程序并按照指示操作。 - 安装完成后同样需要配置环境变量,添加 `%...
官方zeromq the guide... We've also translated most of the examples into C++, C#, CL, Delphi, Erlang, F#, Felix, Haskell, Objective-C, Ruby, Ada, Basic, Clojure, Go, Haxe, Node.js, ooc, Perl, and Scala.
LicenseFinder 能够为你的项目找到许可证依赖项。LicenseFinder 与你的软件包管理器一起使用能够找到其依赖项,能检测到包中的许可证,且许可证还能与用户定义的白名单比较,另外你能够... Objective-C ( CocoaPods)
Elixir是一款免费的函数式编程语言,采用一种动态语言,灵活的语法和宏支持,建立在Erlang虚拟机之上,来构建并发、分布式、容错应用程序及热代码升级。软件功能强大,界面简洁,是您进行函数式编程的首选,需要的...
它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务 ...
解压文件到一个合适的目录,例如`C:\Program Files`。然后找到`rabbitmq_server-3.7.8\sbin`目录下的`rabbitmq-plugins.bat`文件,以管理员权限运行。执行`rabbitmq-plugins enable rabbitmq_management`命令,这会...
需要注意的是,如果遇到安装过程中因下载手册页面失败而卡住的情况,可以使用 Ctrl-c 结束安装,因为这并不影响主要功能的使用。 **二、RabbitMQ 配置** RabbitMQ 的配置主要涉及三个文件: 1. **enabled_plugins...
2. 将下载的二进制包解压到 `/opt` 目录下:`tar xvf rabbitmq-server-generic-unix-3.x.x.tar.xz -C /opt/` 3. 创建RabbitMQ的启动脚本软链接:`ln -s /opt/rabbitmq_server-3.x.x/sbin/rabbitmq-server /usr/bin/`...
RabbitMQ基于Erlang语言开发,它支持多种协议,如AMQP(Advanced Message Queuing Protocol)、STOMP、MQTT等,能与各种编程语言如C++、Java、Python、Node.js等良好集成。 首先,让我们了解RabbitMQ的核心概念。...
- **持续集成/持续部署(CI/CD)**:Jenkins、Travis CI 或 GitHub Actions 可用于自动化构建和部署 Node.js 应用。 ### 6. 错误处理 - **错误第一回调(Erlang风格)**:Node.js 中,错误通常作为回调函数的第一个...
支持的语言包括但不限于C、C++、Java、Objective-C、Scala、Erlang、Node.js、C#和Go。这种语言的多样性极大地方便了跨语言的项目开发,也扩展了ZeroMQ的应用场景。 在ZeroMQ的消息传递模型中,消息由两部分组成:...
Go语言适用于多核并行和网络编程,与Erlang、Node.js、C和Java竞争;在系统编程中,与Java、C++和Shell对抗;在Web开发中,与Java、Python、Ruby on Rails和PHP争夺市场份额;尽管在客户端和移动客户端开发方面相对...
您也可以从CI服务器下载发行版和文档,为: : : 在上可以找到非常相似PHP替代品,在上可以找到Erlang端口。 Nami本身只是一个库,它允许您的nodejs代码与Asterisk Manager Interface(AMI)进行通信。 但是,它...