网站开发报告,有域名建网站,wordpress加载图片的速度,企业网络搭建及应用实验报告http://blog.csdn.net/shimiso/article/details/8156439
前面几篇给大家系统讲解的有关xmpp openfire smack asmack相关的技术和使用#xff0c;大家如果有所遗忘可以参考 顺便也一起回顾下xmpp的历程 xmpp协议起源于著名的Linux即时通讯服务服务器jabber,有时候我们会把xmp…http://blog.csdn.net/shimiso/article/details/8156439
前面几篇给大家系统讲解的有关xmpp openfire smack asmack相关的技术和使用大家如果有所遗忘可以参考 顺便也一起回顾下xmpp的历程 xmpp协议起源于著名的Linux即时通讯服务服务器jabber,有时候我们会把xmpp协议也叫jabber协议其实这是不规范的xmpp是个协议而jabber是个服务器因为jabber开源,设计精良,安全,稳定,跨语言,跨平台,封装开发简便,越来越多人开始使用它,并且逐步完善,不久它便形成了一个强大的标准化体系,Google GTalk、Pidgin、PSI、Spark、Pandion、MSN、Yahoo、ICQ..诸如此类一些软件在这个强大的标准体系下实现了互联.那么XMPP到底是什么意思用通俗的话讲它和基于xml格式的一些协议原理差不多只不过是个针对服务器的软件协议罢了。 那么在java领域是否存在一个类似jabber那么强大开源稳定的也完美支持xmpp协议的服务器呢答案有的那便是openfireopenfire是纯java开发的基于XMPP的协议目前最终版本锁定在了2011年openfire 3.7它一共有linux windows mac 三个版本安装也非常简单openfire这个服务器是个开放式的平台它内部集成的服务包括即时通讯服务会议室服务用户安全验证和管理服务搜索服务组织机构服务会话服务这几大服务都有相应的管理类和对外接口它的二次开发和扩展都是在插件基础上直接嫁接进去的早期有很多第三方为他做了插件有语音服务red5视频服务邮件服务等等语音和视频在openfire上一直是个鸡肋没有非常好的解决方案而做这些插件的大部分都停止更新大家如果选用openfire做视频和语音还要慎重抛开这些插件openfire在IM及时通讯上还是相当强大稳定的不少公司拿它来做二次开发但即便如此openfire的二次开发成本还是比较高昂的笔者曾经成功费了九牛二虎之力将源码环境搭建起来并成功将它与我们JAVAEE 经典架构SSH成功组装用openfire的桌面客户端spark软件和android开源xmpp客户端Beam软件web端聊天软件Claros Chat享受了一把在自己服务器上“随时随地聊天”不过这些都是实验阶段距离成熟可用还很远研究技术可以这么勾兑尝试真的给人用可不能这么随意我们还是要挖掘真正对我们有用的价值 openfire过于庞大繁复许多对我们来说都是没什么用的甚至要砍掉改造能不能有精简的xmpp服务器呢?答案是有的,androidpn,笔者认真比对过openfire和androidpn的源码,最后惊奇的发现,原来它就是从openfire里面庖丁解牛出来的一部分,做这件事的人非常的了不起,为我们省了很大力气,在此感谢他的开源和共享精神,那么androidpn分离出来的是消息推送服务,简言之就是从服务端向android客户端推送消息的服务,因为openfire的源码架构是在jetty基础上建立的,它的启动和部署方式和我们传统的服务器tomcat和weblogic等有点区别,所以androidpn也有jetty的影子,在和我们传统架构组合的时候还要再把它和jetty拆开, androidpn的搭建和使用网上的教程很多,大家可以发现大部分千篇一律,出现一个OK界面就没了,堂而皇之的写上原创,有的只是改了下hello world,如此糊弄,实在难为所用! androidpn消息推送采用的是apache的mina框架做的,服务端和客户端两边都有监听,也就是我们所说的socket编程,有人说socket编程有什么难的,就那么回事,其实不然,我们平时写的socket聊天都只是在局域网的,但是要穿透路由和防火墙,让信息安全及时的传送到另一个网关的局域网电脑中,就不是一件简单的活了,其中涉及到在nat上打洞,还有线程,断网重连,安全加密等等,那么androidpn配合mina相当于把这些活都干了,那么我们要的干活就相对比较精细了,第一学习mina的安装配置的规则,第二学习xmpp协议组装和解析的规则,第三学习androidpn推和收消息的核心代码,如此三点我们便能灵活驾驭住androidpn出现再大的问题自己也能动手去调了。 在和spring整合的时候大家要注意不要让mina服务启动2次笔者整合时候无意发现在linux64位系统weblogic上启动时候总是报5222已经被占用反复查看代码发现mina在随web容器启动过一次5222端口后xmppserver类中的start方法中ClassPathXmlApplicationContext类又加载了一次spring配置导致端口被重复开启两次最后终于发现问题所在 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:contexthttp://www.springframework.org/schema/context xmlns:aophttp://www.springframework.org/schema/aop xmlns:txhttp://www.springframework.org/schema/tx xmlns:utilhttp://www.springframework.org/schema/util xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd context:component-scan base-packageorg.androidpn.server.* /!-- 自动装配 -- !-- -- !-- Resources -- !-- -- bean idpropertyConfigurer classorg.springframework.beans.factory.config.PropertyPlaceholderConfigurer property namelocations list valueclasspath:jdbc.properties/value /list /property /bean !-- -- !-- Data Source -- !-- -- bean iddataSource classorg.apache.commons.dbcp.BasicDataSource destroy-methodclose property namedriverClassName value${jdbcDriverClassName} / property nameurl value${jdbcUrl} / property nameusername value${jdbcUsername} / property namepassword value${jdbcPassword} / property namemaxActive value${jdbcMaxActive} / property namemaxIdle value${jdbcMaxIdle} / property namemaxWait value${jdbcMaxWait} / property namedefaultAutoCommit valuetrue / /bean !-- sessionFactory -- bean idsessionFactory classorg.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean property namedataSource refdataSource / property nameconfigLocation valueclasspath:hibernate.cfg.xml / /bean !-- 配置事务管理器 -- bean idtxManager classorg.springframework.orm.hibernate3.HibernateTransactionManager property namesessionFactory refsessionFactory / property namedataSource refdataSource / /bean !-- 采用注解来管理事务-- tx:annotation-driven transaction-managertxManager / !-- spring hibernate工具类模板 -- bean idhibernateTemplate classorg.springframework.orm.hibernate3.HibernateTemplate property namesessionFactory refsessionFactory/property /bean !-- spring jdbc 工具类模板 -- bean idjdbcTemplate classorg.springframework.jdbc.core.JdbcTemplate property namedataSource ref beandataSource / /property /bean !-- -- !-- SSL -- !-- -- !-- bean idtlsContextFactory classorg.androidpn.server.ssl2.ResourceBasedTLSContextFactory constructor-arg valueclasspath:bogus_mina_tls.cert / property namepassword valueboguspw / property nametrustManagerFactory bean classorg.androidpn.server.ssl2.BogusTrustManagerFactory / /property /bean -- !-- MINA -- bean classorg.springframework.beans.factory.config.CustomEditorConfigurer property namecustomEditors map entry keyjava.net.SocketAddress bean classorg.apache.mina.integration.beans.InetSocketAddressEditor / /entry /map /property /bean bean idxmppHandler classorg.androidpn.server.xmpp.net.XmppIoHandler / bean idfilterChainBuilder classorg.apache.mina.core.filterchain.DefaultIoFilterChainBuilder property namefilters map entry keyexecutor bean classorg.apache.mina.filter.executor.ExecutorFilter / /entry entry keycodec bean classorg.apache.mina.filter.codec.ProtocolCodecFilter constructor-arg bean classorg.androidpn.server.xmpp.codec.XmppCodecFactory / /constructor-arg /bean /entry !-- entry keylogging bean classorg.apache.mina.filter.logging.LoggingFilter / /entry -- /map /property /bean bean idioAcceptor classorg.apache.mina.transport.socket.nio.NioSocketAcceptor init-methodbind destroy-methodunbind scopesingleton property namedefaultLocalAddress value:5222 / property namehandler refxmppHandler / property namefilterChainBuilder reffilterChainBuilder / property namereuseAddress valuetrue / /bean bean idserviceLocator classorg.androidpn.server.service.ServiceLocator scopesingleton / !-- Services-- bean iduserService classorg.androidpn.server.service.impl.UserServiceImpl/ bean idnotificationService classorg.androidpn.server.service.impl.NotificationServiceImpl/ /beans 配置serviceLocator是为了保证spring容器只能由一个上下文也就是spring容器只被启动一次我们将BeanFactory交给了serviceLocator这样一来有什么好处呢 控制层服务层数据库操作层都受spring管理在他们中去跟spring要资源一定是要什么有什么想怎么拿就怎么拿都很方便但是如果想在没有被spring所管理的类中去拿spring的资源动作就不那么优雅了有人建议用ClassPath加载器初始化spring工厂来获取资源问题就处在这里这种做法必定会产生2个spring上下文一个是web容器所启动的一个是java类加载器所启动的我们的MINA服务器也就被启动了2次其实资源被重复多次实例化除了影响性能外对程序影响可能并不大但是MINA被启动2次肯定会出问题的。为保证spring只有一个上下文我们将容器上下文交给了serviceLocator脱离spring管控的环境可以面向serviceLocator来调度spring中的资源操作MINA服务器。
package org.androidpn.server.service; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; public class ServiceLocator implements BeanFactoryAware { private static BeanFactory beanFactory null; private static ServiceLocator servlocator null; public static String USER_SERVICE userService; public static String NOTIFICATION_SERVICE notificationService; public void setBeanFactory(BeanFactory factory) throws BeansException { this.beanFactory factory; } public BeanFactory getBeanFactory() { return beanFactory; } public static ServiceLocator getInstance() { if (servlocator null) servlocator (ServiceLocator) beanFactory.getBean(serviceLocator); return servlocator; } /** * 根据提供的bean名称得到相应的服务类 * * param servName * bean名称 */ public static Object getService(String servName) { return beanFactory.getBean(servName); } /** * 根据提供的bean名称得到对应于指定类型的服务类 * * param servName * bean名称 * param clazz * 返回的bean类型,若类型不匹配,将抛出异常 */ public static Object getService(String servName, Class clazz) { return beanFactory.getBean(servName, clazz); } /** * Obtains the user service. * * return the user service */ public static UserService getUserService() { return (UserService) getService(USER_SERVICE); } public static NotificationService getNotificationService() { return (NotificationService) getService(NOTIFICATION_SERVICE); }
}
在config.properties中还要特别注意xmpp.resourceName必须跟客户端中XmppManager的private static final String XMPP_RESOURCE_NAME AndroidpnClient;保持一致否则连不上服务器还xmpp.session.maxInactiveInterval-1表示永不中断如果设定了时间超过这个时间范围没有任何活动就会自动断开这里的时间单位全部是毫秒。 apiKey1234567890
xmpp.ssl.storeTypeJKS
xmpp.ssl.keystoreconf/security/keystore
xmpp.ssl.keypasschangeit
xmpp.ssl.truststoreconf/security/truststore
xmpp.ssl.trustpasschangeit
xmpp.resourceNameAndroidpnClient ##Added by ken
usernameadmin
passwordadmin #资源名称
resource_nameAndroidpnClient #校验超时时间间隔
xmpp.session.checkTimeoutInterval10000 #Session timeout最大非活动时间间隔
xmpp.session.maxInactiveInterval1000000 在androidpn.properties中端口和IP不要写错有人喜欢写localhost在手机上是无法识别的必须写绝对IP地址。 apiey1234567890 xmppHost192.168.1.78 xmppPort5222 运行结果如下 离线消息也支持先给离线用户发个消息效果如下 在数据库中我们看到有一条离线消息是发给用户4aa50dde313f4b63907c2430bf00b413status为0标记为离线 这时我们再上线大约等待20秒左右查看系统控制台打印 查看android端看看用户4aa50dde313f4b63907c2430bf00b413上线情况 这时候数据库记录发生了变化status变成了2表示已经接收用户点击OK的时候它又变成了3表示已经查看 离线消息的原理相对比较简单当系统给指定用户发送消息时候会首先判断用户是够在线如果在线就直接发送如果没有在线就暂时标记保存等用户上线时候先查离线消息然后弹出其实整个项目都是开源的可能唯一的难点就是对MINA和XMPP协议的不了解再加上本身对socket和多线程的畏惧如果这些全部都掌握驾驭好这套源码还是很有信心的了解其基本原理以后我们就可以放心的做更多的扩展。 网上现在也有不少androidpn版本五花八门什么都有里面到底有没问题改了什么没改什么都不知道基本上已经追溯不到原创到底是谁了索性就只能从国外的一个网站上下了一个比较可靠的版本自己动手去量身改造终于出了一个比较稳定版本。对于消息提醒来说它仅仅是个notification许多人非要把业务数据也做进去更有夸张好几兆的xml数据就这么硬塞提醒过去这种做法本身就背离了设计的初衷非要把跑车当牛车使能不出问题吗其实业务数据还是用http拉比较好xmpp及时的前提是用资源消耗作为代价的我们能适度就适度用用好用稳就行! 项目源码下载: Androidpn威力加强版(4月17日更新) 下载地址http://download.csdn.net/detail/shimiso/5267500
项目