接上篇:

(一)客户端与服务器建立连接

上一篇写到ClientSession createClientSession这里,创建一个客户端的session。在SessionManager类中创建了session之后,这里拼接了两个xml内容的text。一个是Build the start packet response,创建一个头条包,作为回应。另外一个是:XMPP 1.0 needs stream features,是xmpp1.0所需要的文件结构。两个消息的格式内容如下:

<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" 
id="bdef9c6a" xml:lang="en" version="1.0">
<stream:features>
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls>
<auth xmlns="http://jabber.org/features/iq-auth"/>
<register xmlns="http://jabber.org/features/iq-register"/>
</stream:features>

然后,调用connection的deliverRawText方法,将这两个xml内容通过IOSession的writer方法,传输到mina里面。具体mina怎么处理,本人还没有研究过。

到此,根据记录的log日志,此消息已经发布了。客户端与服务器建立连接的过程,这里已经完成。这里只是一部分,关于客户端消息的发送,这部分内容也应该不少。

(二)服务器推送消息

从服务器推送消息的时候,会调用NotificationManager类里面的方法,分别为广播和对单个用户发送。这里主要看广播。

首先是构造IQ消息体,createNotificationIQ方法来构造。

    /**
* Creates a new notification IQ and returns it.
* 构造消息体格式
*/
private IQ createNotificationIQ(String apiKey, String title,
String message, String uri) {
Random random = new Random();
String id = Integer.toHexString(random.nextInt());
// String id = String.valueOf(System.currentTimeMillis()); Element notification = DocumentHelper.createElement(QName.get(
"notification", NOTIFICATION_NAMESPACE));
notification.addElement("id").setText(id);
notification.addElement("apiKey").setText(apiKey);
notification.addElement("title").setText(title);
notification.addElement("message").setText(message);
notification.addElement("uri").setText(uri); IQ iq = new IQ();
iq.setType(IQ.Type.set);
iq.setChildElement(notification); return iq;
}

构造后的xml:

<iq type="set" id="860-0" to="159b356f005e4710a1f1c8aa0547e4ce@127.0.0.1/AndroidpnClient">
<notification xmlns="androidpn:iq:notification">
<id>11218d6c</id>
<apiKey>1234567890</apiKey>
<title>你好</title>
<message>你好啊</message>
<uri></uri>
</notification>
</iq>

在ClientSession中查找指定用户名的session,如果存在,则发送此条IQ消息。调用connectin的deliver方法,通过ioSession.write(buffer),将xml信息传输给mina,并且将发送记录加1。

客户端源码分析:

客户端代码很简单的,依靠xmppmanager维持连接。这里说一下大概流程。

当客户端推送消息过来的时候,NotificationReceiver类的onReceive方法接收到消息,在这里,这时候,已经获得了所有发过来的数据。在这里,已经可以做自己的事情了,因为已经有了需要的数据。不过貌似挺多人喜欢在notifier的notify方法中来进行处理。

其他就是自己的业务了。

还有一个是关于客户端的用户名和密码,这个默认是自动生成,也可以自动指定。在XMPPManager的run方法里面可以修改。修改后会出现一些问题,就是服务器端注册的时候,会出现用户名已经存在,重复插入的问题。这个需要在服务器端插入数据的时候修改一下代码,在UserServiceImpl中修改,为了业务需要,本人把hibernate修改为了mybatis,所以方法略有不同:

    public User saveUser(User user) throws UserExistsException {
try {
//修改为自己的用户登录
try {
user=getUserByUsername(user.getUsername()); } catch (UserNotFoundException e) {
// TODO Auto-generated catch block
log.info(user.getUsername()+" is not exist in db ....");
userDao.saveUser(user);
e.printStackTrace();
}
} catch (DataIntegrityViolationException e) {
e.printStackTrace();
log.warn(e.getMessage());
throw new UserExistsException("User '" + user.getUsername()
+ "' already exists!");
} catch (EntityExistsException e) { // needed for JPA
e.printStackTrace();
log.warn(e.getMessage());
throw new UserExistsException("User '" + user.getUsername()
+ "' already exists!");
}
return user;
}

这样就可以了。

关于短线重连,网上也有很多解决方法,是客户端加一行代码:

 private void addTask(Runnable runnable) {
Log.d(LOGTAG, "addTask(runnable)...");
taskTracker.increase();
synchronized (taskList) {
if (taskList.isEmpty() && !running) {
running = true;
futureTask = taskSubmitter.submit(runnable);
if (futureTask == null) {
taskTracker.decrease();
}
} else {
//解决服务器端重启后,客户端不能成功连接androidpn服务器
runTask();
taskList.add(runnable);
}
}
Log.d(LOGTAG, "addTask(runnable)... done");
}

当然,其他还有许多细节,先到这里,感谢网上那么多博主写的一些资料。

AndroidPn源码分析(二)的更多相关文章

  1. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  2. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  3. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

  4. 十、Spring之BeanFactory源码分析(二)

    Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...

  5. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  6. 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>

    目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...

  7. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  8. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  9. ConcurrenHashMap源码分析(二)

    本篇博客的目录: 一:put方法源码 二:get方法源码 三:rehash的过程 四:总结 一:put方法的源码 首先,我们来看一下segment内部类中put方法的源码,这个方法它是segment片 ...

随机推荐

  1. js 触发 change 事件

    首先,请各位包涵,我本人对 JS 不是很熟,不知道"触发change事件"和"触发onchange事件"哪个更加合适.有园友知道的麻烦指出,先行谢过. 起因是这 ...

  2. OpenCV(图像处理)—访问像素的三种方法

    方法一:用指针访问像素 #include <opencv2/opencv.hpp> #include <opencv2/core/core.hpp> #include < ...

  3. LibreOJ 6277 数列分块入门 1(分块)

    题解:感谢hzwer学长和loj让本蒟蒻能够找到如此合适的入门题做. 这是一道非常标准的分块模板题,本来用打标记的线段树不知道要写多少行,但是分块只有这么几行,极其高妙. 代码如下: #include ...

  4. discrete

    discrete - 必应词典 美[dɪ'skrit]英[dɪ'skriːt] adj.离散的:分离的:各别的 网络不连续的:分立的:离散型

  5. phpStudy1——PHP文件获取html提交的参数

    示例代码: submit.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8" ...

  6. iOS 多页面跳转同一页面时数据处理

    如果 同一个界面, 会有10个数据源传进来, 此时 创建 一个总模型fullmodel 存储 10个model 数据, 创建 10个一样的cell, 在 不同数据, 用不同cell处理最好, 千万别于 ...

  7. 记录java版本不兼容的坑,(kafka运行报错)

    启动kafka报错 错误原因是: 由较高版本的jdk编译的java class文件 试图在较低版本的jvm上运行的报错 解决办法是: 查看java版本 C:\Users\Administrator&g ...

  8. OpenGL.ProjectiveTextureMapping

    1. 简介 https://developer.nvidia.com/content/projective-texture-mapping

  9. linux下给php安装memcached及memcache扩展(转)

    http://kimi.it/257.html (另外的方法)linux安装memcached及memcache扩展一.安装libevent函数库下载地址:http://libevent.org默认被 ...

  10. 用Fiddler抓到的报文Content-Type: application/x-www-form-urlencoded,怎样解析?

    抓到的HTTPS请求报文,在报文头中Content-Type: application/x-www-form-urlencoded 报文体为: entrypoint=clientmanagement& ...