一、 概述
- Openfire最主要的功能是实现XMPP服务器,简单来说,openfire为我们提供一个固定的地址,我们只需要向openfire服务器发送标准的XMPP信息(即XML文件流),那么openfire服务器应当给予我们回应,这里的openfire服务器也可以看做一个容器,我们在聊天时,需要在这个服务器上注册一个会话,在会话存在的时间,我们可以实现即时聊天的一些常用功能,比如建立自己的组,添加好友,聊天,以及传送文件等等,同时,openfire服务器也需要实现自己的管理界面,这样openfire服务器也扮演一个web容器的角色
- Openfire是开源的实时协作服务器(RTC),它是基于公开协议XMPP(也成为Jabber)消息的。
- 使用它轻易的构建高效率的即时通信服务器。
- Openfire的核心功能可以概括为:连接管理、消息解析、消息路由、消息发送。
- Openfire具有跨平台的能力,Openfire与客户端采用的是C/S架构,一个服务器要负责为连接在其上的客户端提供服务。
- Openfire客户端有spark, pidgin, Miranda IM, iChat等,用户如果自己开发客户端,可以采用遵循GPL的开源Client端API--Smack。
- Openfire服务器端支持插件开发,如果开发者需要添加新的服务,可以开发出自己的插件后,安装至服务器,就可以提供服务,如查找联系人服务就是以插件的形式提供的。
二、 体系架构
三、 功能模块
- Pubsub:Publish/Subscribe,这使得xmpp实体能够在pubsub服务上创建nodes(topics),并且发布信息。一个事件通知将广播到所有订阅了这个节点的实体上。
- Pep:(Personal Eventing Protocol)使用XMPP publish-subscribe协议广播状态改变事件、及时消息和出席帐户到其他用户。
- Stun:为p2p会话提供地址发现服务,如:媒体传输和UDP包的收发。
- Router:内部的路由,把相应的包路由给相应的处理器。
- Muc:(Multi-User Chat)用户可以交换文本信息在room或者channel上下文中,版主或者管理员有权踢除用户和禁止用户。
- 所有Module都需要实现Module接口,该接口中定义了模块生命周期中需要调用的方法
四、 数据模型
- 数据库表设计:详见:
- Openfire的数据库处理采用直接调用JDBC 的方式。核心类为org.jivesoftware.database.DbConnectionManager。数据库的处理与业务处理耦合,没有划分出专门的业务逻辑层。
- 3. ConnectionProvider,此类为数据库提供者接口,如需连接mysql、hsqldb等数据库,需首先实现些接口,通常直接调用XXManager中的实例方法,XXManager中又调用的是对应的接口XXProvider的方法,实际操作在该接口的实现类中实现。实现类是动态绑定的(默认的实现类通常命名规则为DefaultXXProvider),在运行时根据ofproperty表中对应配置项值选
- org.jivesoftware.database.DbConnectionManager,连接管理类
- org.jivesoftware.util.JiveGlobals,通常用于操作ofproperty表中记录
- 1. XMPP协议
五、 通信机制
1) XMPP(Extensible Messageing and Presence Protocol:可扩展消息处理现场协议)是目前主流的四种IM(IM:instant messaging,即时消息)协议之一,其他三种分别为:即时信息和空间协议(IMPP)、空间和即时信息协议(PRIM)、针对即时通讯和空间平衡扩充的进程开始协议SIP(SIMPLE)。
2) XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议。
3) 核心的XML流传输协议 ,基于XML FreeEIM流传输的即时通讯扩展应用,XMPP的扩展协议Jingle使得其支持语音和视频
4) XMPP协议在PC和Android分别有对应的协议实现smack和asmack,不用我们写XML协议解析
5) XMPP的基本网络结构:Client、Server、Gateway,通信能够在这三者的任意两个之间双向发生。服务器同时承担了客户端信息记录,连接管理和信息的路由功能。网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信),MSN,ICQ等。
6) 客户端利用xmpp(基于TCP/IP)访问server,传输的是XML,工作原理是:
a) 节点连接到服务器;
b) 服务器利用本地目录系统中的证书对其认证;
c) 节点指定目标地址,让服务器告知目标状态;
d) 服务器查找、连接并进行相互认证;
e) 节点之间进行交互
7) XMPP协议的传输是通过XML文件来传输的,并且不是类似于QQ的点对点通讯,而是客户端到服务器再到客户端的方式来实现,以上过程的一个简单的XMPP通讯流程可以如下:
a) 首先,由客户端连接到服务器,客户端通过IO流发送一段XML文件,在文件中包含了自身的用户名和密码
b) 服务器端接收到客户端的XML文件,从中获取用户名和密码进行验证,如果验证成功,服务器会发送一个XML文件给客户端表明已经登录成功
c) 登陆成功后,客户端可以通过发送一个获取好友名单的XML文件,服务器会将当前用户的好友以XML文件传到客户端
d) 客户端选择一个好友,向其发送信息(其实是向服务器发送,服务器收到后会转发给对应的好友),好友收到
8) XMPP地址模式:JID=[ node”@” ] domain [ “/” resource ](如:cyber@cyberobject.com/res),domain:服务器域名,node: 用户名,resource:属于用户的位置或设备。一个用户可以同时以多种资源与同一个XMPP服务器连接
9) XMPP xml消息格式定义:
<stram>
<presence> //此元素确定用户的状态
<status/>
</prensence>
<message> //用于两个用户之间发送信息
<body/>
</message>
<iq> //信息/请求,是一个请求-响应机制,管理xmpp服务器上两个用户的转换,允许他们通过相应的xml格式的查询和响应
<bind/>
</iq>
</stream>
10) XMPP的安全机制:XMPP采用SASL作为身份认证协议,XMPP采用TLS的“START-TLS”扩展来为通信双方提供加密性和数据完整性服务
11) XMPP体系架构:XMPP server:其内核是一个XMPP路由器,完成基本组件间的数据包交换和路由。功能:1.会话管理器:负责客户端会话认证,在线状态,用户联系表等;2.数据存储器(XDB):连接数据库系统,保持用户信息、通信日志等;3.连接器管理器:管理与客户端之间的连接;4.服务器连接器:管理xmpp服务器之间的连接;5.传输器:建立xmpp服务器与非xmpp服务器通信
12)
- 2. Apache MINA框架
1) XMPP协议是基于TCP/IP协议进行传输的,在openfire中,应用了apache的mina框架作为NIO框架,简单的来说,openfire服务器用mina框架建立一个简单的服务器,可以接收和发送基本的IO流,然后在此基础上把接收到的IO流解析为XML文件,然后在根据XMPP协议对XML文件进行操作
2) 是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可靠性的网络应用程序。它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的事件驱动的异步API,对通信功能进行扩展
3) 为不同的传输类型(TCP/UDP)提供了统一的API
4) 过滤器作为一个扩展特性,类似Servlet过滤器
5) 低级(字节缓存)和高级(用户定义的消息对象和编码)的API
6) 高度定制化线程模型(单线程/线程池)
7) 超载保护和传输流量控制
8) Openfire的ConnectionHandler类继承了MINA的IoHandlerAdaper,他主要负责连接的创建、销毁,以及接收到XML数据包的投递。ConnectionHandler有三个子类,其中ClientConnectionHandler负责客户端与服务器端的连接,ComponentConnectionHandler负责组件与服务器端的连接,类图如下:
- 3. Openfire的socket网络连接
1) 服务器和服务器之间的连接(监听在端口5269)
2) 外部组件和服务器之间的连接(监听在端口5275)
3) 多元(complex)连接(监听在端口5269)
4) 客户端和服务器的连接(监听在端口5222)
5) 和客户端通过TLS/SSL3.0和服务器的连接。(监听在端口5223)
6) 连接都是通过ConnectionManager接口实现管理的,程序中对ConnectionManager接口的实现类是ConnectionManagerImpl,它是作为一个模块(Module)类加载到服务器中的
六、 开发配置
- 环境配置:
1) http://blog.csdn.net/kingsonl/article/details/7730225
2) http://blog.csdn.net/nomousewch/article/details/6534555
- 2. Openfire源码目录结构
1) build目录:build目录下收录的是生成安装文件(例如:rpm)所要的一些文件,例如JRE等
2) resources目录:resources目录下收录的是一些为实现国际化(i18n)和本地化的一些编码文件(例如:英文,中文,法文,德文等)
3) documentation目录:documentation目录下收录的是一些关于Openfire安装和配置的信息,但最终要的是这里有Openfire开发的Javadoc
4) src目录:顾名思义这个src文件夹就是我们想要的Openfire源代码了,这下面又有许多文件夹,我们只要Java文件夹就好,这里面实现的Openfire的核心功能,通过它就可以调试Openfire了
- 3. 命名规则
Openfire中常见的类名后缀命名包括Starter、Plugin、Listener、Dispatcher、Handler、Manager、Provider,通常情况下,这些命名类包括如下意义:
1) XXStarter:系统启动类
2) XXListener:业务的最终处理类
3) XXDispatcher:调度类,其中有很多关键方法,如addListener(),以组合的方式,为类内定义的静态Set<XXListener>实例添加XXListener对象。以便调用dispatchEvent(String property, EventType eventType, Map<String, Object> params)方法遍历处理Set集中的XXListener对象(通过调用XXListener对象的各实际方法完成实际业务)
4) XXPlugin:实现Plugin接口的插件类,需实现initializePlugin(PluginManager manager, File pluginDirectory)方法和destroyPlugin()方法。在其初始化方法中调用Dispatcher实现类的addListener()方法如PropertyEventDispatcher.addListener(this)
5) XXProvider:实现面向接口编程方式的接口类,通过反射机制创建具体实现类的对象,反射类名配置在ofproperty表对应的记录propvalue属性中。若没有相关配置,则调用默认实现类,默认实现类类名命名规则为DefaultXXProvider
6) XXHandler:实际处理类,以ConnectionHandler为例,在org.jivesoftware.openfire.spi. ConnectionManagerImpl类的startClientSSLListeners(String localIPAddress)方法中,有这样一段代码:sslSocketAcceptor.bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler(serverName));其中bind方法的第二个参数是新创建的一个ClientConnectionHandler的实例,而它就是ConnectionHandler的一个子类
- 4. 系统配置
Openfire的系统配置项采用文件结合数据库表的方式配置,也有部分默认配置项通过Java硬编码方式配置(如org.jivesoftware.openfire. ConnectionManager接口类中定义的DEFAULT_PORT、DEFAULT_SSL_PORT、DEFAULT_COMPONENT_PORT等),Openfire中比较重要的配置位置包括:
1) src/conf目录下的openfire.xml配置文件。该配置文件为系统核心配置文件。在第一次启动Openfire并通过管理控制台完成安装配置后会往该配置文件中填入相应的配置信息
2) plugin.xml配置文件。该配置文件为各插件包下的核心配置文件,由它确定插件核心处理类和相应页面插件的展现等。配置项及含义详见官方插件开发说明部分
3) web.xml和web-custom.xml配置文件。用于配置servlet和用户自定义servlet(插件页面用,放在插件对应目录下)
4) ofproperty中的各条记录,该表中包括两个字段name和propvalue,分别代表配置项名和配置项值
- 5. Openfire启动过程
系统启动时调用org.jivesoftware.openfire.starter.ServerStarter类中的start()方法,加载org.jivesoftware.openfire.XMPPServer类,并调用这个类的start(),Start()方法中首先调用verifyDataSource()方法验证并确保数据库可以访问,然后会调用 loadModules();initModules();startModules();方法来对Module接口的实现类的各子类进行操作,依次完成模块的加载、初始化和启动操作。loadModules()方法中会调用loadModule(String module)方法通过反射加载各模块类,参数字符串module为对应的模块核心处理类的类名
- 6. 消息处理流程
在Openfire服务器对XMPP的实现中,消息被封装为Packet对象,因此Openfire服务器的核心代码是对客户端Packet对象的监听和处理流程
Packet处理流程:
1) 首先,Openfire服务器需要启动一个基于TCP/IP的监听服务,用以接收客户端传过来的XML流文件。这个过程在XMPPServer类的start()方法中进行,这个监听服务是以loadModule(ConnectionManagerImpl.class.getName())来加载,调用ConnectionManagerImpl类的createClientListeners()方法
2) 其中的socketAcceptor是在buildSocektAcceptor()方法中定义的,它是作为一个服务端的接收器,是mina框架为我们封装好的一个socketserver,在上面这个方法中,我们为socketAcceptor添加了一个过滤器,XMPPCodeFactory,这个类将过滤xmpp相关请求,加以处理,我们再看同一个类的另外一个方法startClientListener()
3) 其中的socketAcceptor.bind()方法启动了监听服务器,来监听所有发送到服务器5222端口的数据,并用ClientConnetionHandler类来处理,ClinetConnectionHandler继承于ConnectionHandler类,后者实现了mina的IoHandlerAdaptor接口,其中的messageReceived()方法是关键
4) 可以看到收到的信息交由StanzaHandler的process方法中进行XML解析并封装为packet对象,然后再进行下一步的处理,至此,从客户端到服务器端的packet传递结束,如下图所示:
- 7. Spark 登录过程-安全认证
1) Spark登录过程消息截图:
2) Spark登录过程中的XMPP消息含义:
- 8. WEB服务器
1) Openfire采用内置的jetty作web服务器,在启动AdminConsolePlugin插件时调用startup()方法启动jetty服务器,9090为其明文端口,9091为其加密端口
2) Openfire没有采用现在很流行的技术架构(SSH),只使用JSP+JavaBean,但是它有自己的系统设计,就连日志都是自己做的,没有使用我们熟悉的log4j
3) 现有的Openfire管理控制台可采用插件方式进行扩展,页面采用Jsp方式实现,页面直接调用业务处理逻辑类(通常命名为XXManager)的实例方法,通常通过request对象封装的方式传递页面展现判定变量,常出现本页跳转。每个插件可定义自己的Servlet类和web.xml及web-custom.xml配置文件
4) 页面展现采用装饰框架方式,decorator页面有两个,即src/web/decorators目录下的两个页面main.jsp和setup.jsp。采用自定义的admin标签实现,标签库admin.tld放置在src/web/WEB-INF目录下,标签解析类放置在org.jivesoftware.admin包下,有SidebarTag、SubnavTag、SubSidebarTag、TabsTag四个解析类。在调用loadPlugin()方法进行插件加载时,解析插件的plugin.xml配置文件,将获取的相关信息封装在AdminConsole类的generatedModel对象中,后期通过插件解析类提取该对象中的数据并配合sitemesh装饰器进行页面展现。
社交app实战如下图:
沟通联系qq:2729404527 微信:code588