do_call(N, {call,M,F,A,group_leader()}, infinity)
gen_server:call({?NAME,Node}, {call,M,F,A,group_leader()}, infinity)
gen:call(Name, '$gen_call', {call,M,F,A,group_leader()}, Timeout)
{'$gen_call', {pid(), reference()}, {call,M,F,A,pid()}}
receive {Mref, Reply} -> erlang:demonitor(Mref, [flush]), {ok, Reply};
ErlMessage
,ETERM
两个重要结构体:
* ``` typedef struct { union { Erl_Integer ival; Erl_Uinteger uival; Erl_LLInteger llval; Erl_ULLInteger ullval; Erl_Float fval; Erl_Atom aval; Erl_Pid pidval; Erl_Port portval; Erl_Ref refval; Erl_List lval; Erl_EmptyList nval; Erl_Tuple tval; Erl_Binary bval; Erl_Variable vval; Erl_Function funcval; Erl_Big bigval; } uval;
} ETERMhtml
* **`erl_interface.h`,`ei.h`几个重要函数:** * ```ErlMessage emsg = {}``` ```erl_receive_msg(fd, 0, 0, &emsg)``` emsg.msg里面存放的结构就是上面{'$gen_call', {pid(), reference()}, {call,M,F,A,pid()}}三元组,若是这里是进行响应远程节点的rpc:call的话返回须要构建{reference(), data}使用erl_send进行反馈给远程节点 * ```erl_element(2, emsg.msg)``` 取元组emsg.msg中第2个位置上的ETERM*对象地址,注意查看C\C++源码发现使用此方法以后就从元组中抽象移除了这个地址的遍历指引,因此只要使用erl_element函数取出来的临时指针对象都必须经过erl_free_term释放,未取的不须要显示调用删除由于删除元组会遍历它全部子元素。这种相似于浅拷贝应用范畴 * ```erl_free_term(emsg.from) ``` ```erl_free_term(emsg.msg)``` 这两行释放必须存在 * rpc互通的数据最好是经过binary或者json可进行序列化,反序列化封装与解析 * **** ## C节点(client) * ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "erl_interface.h" #include "ei.h" int main(int argc, char **argv) { int fd; int loop = 1; int got; ErlMessage emsg; erl_init(NULL, 0); struct in_addr addr; addr.s_addr = inet_addr("127.0.0.1"); if (erl_connect_xinit("idril", "cnode", "cnode@127.0.0.1",&addr, "be3", 0) == -1){ erl_err_quit("erl_connect_xinit"); } if ((fd = erl_connect("temp@10.0.1.85")) < 0){ erl_err_quit("temp@10.0.1.85"); } fprintf(stderr, "Connected to temp@10.0.1.85\n\r"); while (loop) { got = erl_receive_msg(fd, 0, 0, &emsg); if (got == ERL_TICK) { } else if (got == ERL_ERROR) { loop = 0; } else { if (emsg.type == ERL_REG_SEND) { ETERM * fromp = erl_element(2, emsg.msg); ETERM * tuplep = erl_element(3, emsg.msg); ETERM * call = erl_element(1, tuplep); ETERM * mod = erl_element(2, tuplep); ETERM * func = erl_element(3, tuplep); ETERM * arg = erl_element(4, tuplep); /* print */ printf("远程rpc:%s %s:%s\r\n", ERL_ATOM_PTR(call), ERL_ATOM_PTR(mod), ERL_ATOM_PTR(func)); /* 消息发送着进程pid(),与接收引用ref() */ ETERM* from = erl_element(1, fromp); ETERM* mref = erl_element(2, fromp); ETERM* resp = erl_format("{~w, ~i}", mref, 50001); erl_send(fd, from, resp); erl_free_term(emsg.from); erl_free_term(emsg.msg); erl_free_term(fromp); erl_free_term(tuplep); erl_free_term(call); erl_free_term(mod); erl_free_term(func); erl_free_term(arg); erl_free_term(from); erl_free_term(mref); erl_free_term(resp); } } } }
rpc:call('cnode@127.0.0.1', mod, func, [0]). 50001 (temp@10.0.1.85)3>