JXTA源码分析

来源:互联网 发布:单端口环路检测 编辑:程序博客网 时间:2024/04/29 20:19

JXTASun推出的一个P2P计算平台,设计的初衷是一个提供基础的P2P计算功能,它改进了目前已有P2P系统的一些不足之处,比如直接支持许多地址解析和物理层协议、用Java开发带来的平台独立性和可用于PC之外的物理设备等多样性。

 

JXTA也因为领域不同而分了JXSEJXME两个方向,跟J2SEJ2ME一样,后者都是用于移动设备平台开发的库。笔者先从JXSE开始,通过源码阅读分析来研究JXTA的原理和特点。目前JXTA的最新版本是2.5。官方网站是https://jxta.dev.java.net/

 

相信大家都用过Java里的SocketServerSocket了,Jxse在遵循它自己的基础协议情况下也提供了JxtaSocketJxtaServerSocket两个higher-level的通信类。这里就先来看看它们的内部如何实现的:

 

ØJxtaServerSocket

先看看该类的声明:

 

可以看到它其实是继承了java.net.ServerSocket类并实现了自身协议的通用消息监听接口的(可以回想一下Design Pattern的观察者模式)。

 

该类的成员数据包含的一些关键变量举例如下:

 

 

首先按照Jxta的协议所有的通信其实都是通过XML或者Binary的格式来进行,这里的Message类就是它自身对通信内容的一个XML封装,类似reqPipeTag这样的String静态常量还有很多个,JxtaServerSocket通过serverPipe这个管道来监听所有请求连接,由于实现了PipeMsgListener当有Pipe消息到达时会触发pipeMsgEvent方法来处理Pipe消息,通信格式是XML,处理方式首先是把收到的Message压入queue中去排队。

 

在继承自ServerSocketaccept方法中,就开始从queue中依次去除Message对象,遍历寻找之前提到静态常量的那些Tag里的内容,至少都会包含对方请求连接者的PeerPipe信息,Jxta的通信都是Peer(同位体)之间通过建立Pipe进行的。成员变量中的BACKLOG就是queue中默认的消息数量50TIMEOUT就是等待连接建立的默认超时60秒。

 

真正拿到Message建立连接是通过一个processMessage方法,它首先从Msg XMLTag中找到对方Peer的标识即Advertisement、是否需要认证、对方Peer所属的Group信息、是否要求建立raliable的连接等等。所有参数找齐全之后调用JxtaSocket的一个protected签名(只内部使用)的构造函数完成与对方的连接建立。

 

值得一提的是它重写的close方法里,首先关闭了一直监听连接请求的serverPipe、清空消息队列queue,之后会往队列中放一个空消息QUEUE_END_MESSAGE,这样的目的是在accept中成功的跳出一个while(true)的循环。

ØJxtaSocket

接着上面的分析,先看看JxtaSocket中那个被JxtaServerSocket内部调用真正建立连接的构造函数:

 

 

 

它在将这一系列参数赋值给自己的成员变量之后,主要是走了一个bind()->connect()的流程,完成这个流程之后构造了一个connectResponseMessage通过PipeService的监听服务发送出去。这里有个细节是JxtaSocket通过一个boolean型变量initiator来标识谁是连接发起方,那么在这个由JxtaServerSocket内部调用完成连接的函数里就自然把initiator赋值为false了,因为连接是Socket Client发起的嘛。

 

接下来看看bind()->connect()流程:

bind方法做的事很简单,从Pipe Server里构造通过一个Advertisement构造了出一个InputPipelocalEphemeralPipeIn。这里对于不熟悉Jxta的朋友稍微解释一下,Jxta的协议有非常严谨的标识(Indentifier)过程,任何一个通信同位体Peer或者一个同位体组Peer Group,或者一个用于通信的Pipe都需要一个唯一的标识。Jxta使用Advertisement(广告)来发布一个新的标识,所以构造出任何一个Peer/Group/Pipe都需要提供一个实现准备好的Adv(广告)。说白了这样在通信的过程中,Jxta的服务可以很方便的定位查找鉴别任何一个标识对应的是什么玩意。

 

connect()方法中主要是初始化各种通信的管道,其中内置的Outgoing对象被reliable的连接模式下的output/input stream用于发送所有Message。如果是reliable模式,输入输出分别使用的是RaliableInputStream/ReliableOutputStream,非reliable模式输入输出流使用的是JxtaInputStream/JxtaOutputStream

 

Outgoing是通过在构造函数中拿到对方的Group/Pipe/Peer的所有Adv之后利用Endpoint Service提供的通信协议管道服务构造出来的。这样说可能比较难理解,还是得结合一下背景,Jxta这个平台本身提供了许多协议,主要是用于Peer之间发布各自能提供的服务、或者各Peer之间通信、或者各个Peer Group之间产生某种协作关系共享一些信息阿之类的。所以只要使用Jxta的任何class来建立通信,首先都会加入到一个Jxta网络中去,基本的几个服务已经就默认的开始工作了(类似安全认证那些服务需要由用户自己配置才会启用)。说白了就是ClientServer端都自愿加入进了Jxta网络,它会帮助你请求建立Socket连接的时候转发一些Message,引导你的管道或者Stream能顺利的连接到对方。这样的好处是双方都是主动加入了JxtaP2P计算网络,它就能帮助各个Peer通信不受防火墙的阻碍,可以穿透NAT通信等等。(关于NAT穿透原理之前有转载一些文章介绍)

 

Jxta网络就像一个交通警察一样,帮助疏通各Peer之间通信的通道,在遇到Firewall时候它会告诉某Peer对方无法连过来,得你连过去,起到一个指挥的作用。

 

由于Jxta国内使用还不多,太多细节无法一一介绍,讲得可能比较乱,希望大家见谅!

下次将深入到raliable和非-reliable的具体管道类里面看看data是如何发送和接受的。