jinterface包详解

jinterface阅读总结

一.jinterface简介

jinterface是用来与erlang node通信的一个java包。由于大多东西都已经封装好了,所以使用起来非常方便。它伪装自己是一个节点,在erlang程序看来,它就是一个erlang node

二.jinterface组成

jinterface中有很多类,我觉得可以分为两种,一种是基本数据类型的分装,一种是与erlang通信的类。
基本数据类型主要以OtpErlang开头。使用起来十分简单,例如创建两个{hello, world}的元组如下:

OtpErlangAtom hello = new OtpErlangAtom("hello");
OtpErlangAtom world = new OtpErlangAtom("world");
OtpErlangTuple tuple = new OtpErlangTuple(new OtpErlangObject[]{hello, world});

所有的erlang基本类型都是从OtpErlangObject继承,所以一个其他类型数据类型都可以很方便转成OtpErlangObject.在这些类中封装了简单的对这些类型的操作。比如得到其中的值,序列化等等。

  • AbstractNode类:虽然这个类叫做AbstractNode,但是它并不是一个abstract类,不过它的构造函数是protectd,所以不能直接构造此类,只能继承。构造函数接受0个参数或者接受一个主机名跟一个cookie作为参数。在AbstarctNode类加载的时候,会初始化localhost跟默认cookie。类中还有一些其他字段,进行了一些简单封装。

  • OtpLocalNode类:此类继承AbstractNode类,所以也需要跟父类一样的参数作为构造函数,此类提供主要提供了创建pid,创建port,创建ref等函数。这些函数主要依照一定的格式创建对应的数据类型。比如pid:分为两个部分,一个部分是pidCount,一个部分是serial,pidCount不断增加当pidCount超过32767时把serial+1,pidCount归零。serial超过8191时归零。port的规则是:超过268435455时归零。ref的规则是:ref内部用int[3]表示,当int[0]超过262143时,int[1]+1并把int[0]归零,而int[2]只在int[1]==0时自增。由于溢出后会变成最大负数,所以相当于把int 当做unsigned int来使用。

  • OtpNode类:此类继承自OtpLocalNode,所以自带主机名跟cookie和创建pid,port,ref的能力。并且在构造函数中多了一个port的参数。在这个类中有两个内嵌类,有着重要的作用,它们是Acceptor和Mailboxes,先说说Acceptor类,此类继承自Thread,也就是说此类可以可以调用start方法创建一个线程,线程运行此类的run方法。在OtpNode初始化的时候会初始化Acceptor类,此类会初始化必要字段,创建与epmd通信的监听端口,并把端口通过OtpEpmd发送给epmd。然后调用start创建线程运行run方法,在run方法中不断接受监听的sock到来的链接,并放到OtpNode的hashtable中。其他方法都是初始化或者关闭的时候释放资源。Mailboxes类:此类中有两个hashtable如下(WeakReference表示弱引用,不加引用计数):
    private Hashtable<OtpErlangPid, WeakReference> byPid = null;(pid到otpmobx的映射)
    private Hashtable<String, WeakReference> byName = null;(string到otpmbox的映射)
    Mailboxes类提供创建OtpMbox的函数,实现方法是构造出OtpMbox并存放到两个hashtable中。 剩下的函数就是通过名字得到OtpMbox,根据pid得到OtpMbox等待。大概来说,Acceptor主要是向epmd注册,并接受到来的连接。Mailboxes主要是创建OtpMbox并提供索引。现在我们回头看看OtpNode类的其他方法:创建OtpMbox什么的主要调用Mailboxes类,有个非常有用的ping方法,主要实现是通过OtpMbox的send函数发送一定格式的数据再通过返回的数据判断是否连通,稍后我们再来看OtpMbox类。其他跟消息发送有关的函数都通过创建一个OtpMbox来实现。还有就是提供对连接节点的管理。比如移除连接,添加连接等。

  • GenericQueue类:此类用链表的方式实现了一个通用的队列,提供获取,插入等操作,提供同步的get的操作等

  • OtpEpmd类:主要负责跟epmd进行通信,提供查找端口等方法。

  • OtpMbox类:OtpMbox类,提供获取消息的方法,而消息的来源是从OtpNode中的OtpCookedConnection字段新开一个线程不断读取消息,然后路由到各个OtpMbox.

  • OtpCookedConnection类:继承至AbstractConnection类,主要实现AbstractConnection中的dliver方法,把消息路由到何处,而OtpCookedConnection则把消息路由到OtpNode得OtpMbox下。

  • OtpConnection类:此类也继承AbstractConnection类,它有着自己的消息队列,所以把消息存放在自己的队列中。

  • OtpMsg类:封装消息必要的信息,比如消息从哪儿来,到哪儿去,消息的内容等等。

  • OtpOutputStream类:继承至ByteArrayOutputStream,提供对erlang消息的读取,我们知道,erlang节点之间进行消息通信,使用的是external格式,在erlang中可以使用term_to_binary进行转换,那么这个类就负责解析这个格式,得到相应的数据。

  • OtpPeer类:非常简单,继承至AbstractNode,抽象出一个远程节点,其中主要存储了远程节点的节点名字,提供连接此节点的函数,返回一个OtpConnection类。

  • OtpSelf类:继承至OtpLocalNode类,初始化创建一个监听端口,提供对epmd进行交互。

jinterface使用了多线程来读取网络数据,并没有使用epoll等技术,所以还能进一步优化。

三.jinterface使用例子

下面来看一个小例子,然后结合上面的介绍,看看是如何与erlang结点进行通信的。

public class Main {
    public static void main(String[] args) {
	// write your code here
        try {
            Runtime.getRuntime().exec("/usr/local/bin/epmd -daemon");//先启动epmd程序
            OtpNode node = new OtpNode("client@127.0.0.1", "erlang");//就像我们前面介绍的,这一步创建一个节点,在初始化函数中会创建一个acceptor,它向epmd注册自己监听的端口,并不断的接受连接的节点,并把接受的连接存在一个hashtable中,连接用OtpCookedConnection类来表示,它会不断的读取到来的消息,并放到对应的mbox中。
            OtpMbox mbox = node.createMbox("client");//创建一个mbox,这样OtpCookedConnection就能把相应的消息路由到其中的队列。
            while (true){
                OtpErlangObject msg = mbox.receive();//不断的从mbox的队列中取出消息。
                System.out.println(msg.toString());//打印出来。。。
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

四.存在的问题

  1. 由于OtpErlangString 不是继承自OtpErlangList,所以发过来的空字符串会变成列表对象。而且Unicode字符串发过来是列表的codepoint,所以字符串最好还是使用二进制。

五.各家资料

  1. http://www.erlang.org/doc/apps/jinterface/jinterface_users_guide.html
  2. http://www.erlang.org/doc/apps/jinterface/java/com/ericsson/otp/erlang/package-summary.html
  3. http://blog.csdn.net/mycwq/article/details/38448813
原文地址:https://www.cnblogs.com/quitboy/p/4907394.html