为EFS提供C API
问题:
EFS是我最近学习Erlang的过程中写的一个mini分布式文件系统,仿GoogleFileSystem。希望给它提供一套CAPI,以方便利用现有的C库,如与NFSv3,或Fuse的整合。用Erl_interface库可以很easy的做到这一点,这是否从C调用Erlang的唯一方法?Port或linked-inPort是Erlang调C实现的功能,Port是在Erlang一方启动外部程序的,反过来行吗?(由port所启动的外部程序作为server,提供capi,也是可行的,按面向对象的理解,进程作为对象,提供服务作为接口)。
本质上,不管Port,还是Erl_interface,不同语言都是通过IPC机制来实现通信的,类似socket通信,要处理的是通信协议,链接管理,数据的编码和解码等。Erl_interface能极大的简化这些任务。
Portsprovidethebasicmechanismforcommunicationwiththeexternalworld,fromErlang'spointofview.Theyprovideabyte-orientedinterfacetoanexternalprogram.Whenaporthasbeencreated,Erlangcancommunicatewithitbysendingandreceivinglistsofbytes(notErlangterms).Thismeansthattheprogrammermayhavetoinventasuitableencodinganddecodingscheme.
ACprogramwhichusestheErl_InterfacefunctionsforsettingupaconnectiontoandcommunicatingwithadistributedErlangnodeiscalledaCnode,orahiddennode.ThemainadvantagewithaCnodeisthatthecommunicationfromtheErlangprogrammer'spointofviewisextremelyeasy,sincetheCprogrambehavesasadistributedErlangnode.
大概思路如下:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include "erl_interface.h" #include "ei.h" #include "efs.h" int erlang_fd = -1; /* -------------------------------------------------- */ /* API */ /* -------------------------------------------------- */ int efs_init() { int ret, fd; erl_init(NULL, 0); if (erl_connect_init(1, "secretcookie", 0) == -1) erl_err_quit("erl_connect_init"); if ((fd = erl_connect("e1@uss")) < 0) erl_err_quit("erl_connect"); fprintf(stderr, "Connected to e1@uss\n\r"); erlang_fd = fd; return 0; } int efs_destroy() { return 0; } int efs_create(const char *path, int mode) { int ret; ETERM *args; ETERM *reply; args = erl_format("[~s]", path); reply = erl_rpc(erlang_fd, "efs", "create", args); if (reply == NULL) { ret = EINVAL; fprintf(stderr, "error %d\n", ret); goto err_ret; } erl_free_term(reply); erl_free_term(args); return 0; err_ret: erl_free_term(args); return ret; } int efs_close(int fd) { return 0; } /** * test utilities. * create fcount files, every file size is fsize. */ int efs_shell_ww(int fcount, int fsize) { int ret; ETERM *args; ETERM *reply; args = erl_format("[~i,~i]", fcount, fsize); reply = erl_rpc(erlang_fd, "efs_shell", "ww", args); if (reply == NULL) { ret = EINVAL; fprintf(stderr, "error %d\n", ret); goto err_ret; } erl_free_term(reply); erl_free_term(args); return 0; err_ret: erl_free_term(args); return ret; } /* -------------------------------------------------- */ /* Entry point */ /* -------------------------------------------------- */ int main(int argc, char **argv) { int ret; efs_init(); ret = efs_create("afile", 0644); ret = efs_shell_ww(100, 1024*1024); return 0; }