zoukankan      html  css  js  c++  java
  • 基于XMPP协议的aSmack源码分析【1】

    在研究如何实现Pushing功能期间,收集了很多关于Pushing的资料,其中有一个androidnp开源项目用的人比较多,但是由于长时间没有什么人去维护,听说bug的几率挺多的,为了以后自己的产品稳定些,所以就打算自己研究一下asmack的源码,自己做一个插件,androidnp移动端的源码中包含了一个叫做asmack的jar。

    Reader和Writer

    在asmack中有两个非常重要的对象PacketReader和PacketWriter,那么从类名上看Packet + (Reader/Wirter),而TCP/IP传输的数据,叫做Packet(包),asmack使用的是XMPP协议,XMPP简单讲就是使用TCP/IP协议 + XML流协议的组合。所以这个了对象的作用从字面上看应该是,写包与读包,作用为从服务端读写数据。

    PacketWriter中一定含有一个Writer对象,这个Writer是一个输出流,同样的PacketReader对象中有一个Reader,而这个Reader是一个输入流,Writer和Reader对象就是一个简单的读写器,他们是从socket对象中获取出来后,经过装饰变成现在这个样子。

    reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
    writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
    

      

    没有什么神奇的地方,主要看PacketWriter/Reader,这两个对象分别把对应的Writer和Reader引用到自己的内部进行操作,下面就先看一个PacketWriter。

     1  /**
     2      * Creates a new packet writer with the specified connection.
     3      *
     4      * @param connection the connection.
     5      */
     6     protected PacketWriter(XMPPConnection connection) {
     7         this.queue = new ArrayBlockingQueue<Packet>(500, true);
     8         this.connection = connection;
     9         init();
    10     }

    还有就是PacketWriter初始化的时候将XMPPConnection对象传了进来,因为在init方法中使用到了XMPPConnection对象的writer成员,我想说的是,为什么不直接传递writer成员?而是将整个对象XMPPConnection传了过来?其实这就是设计模式的好处,我们如果每次都传递的是自己的成员,那么如果后期有改动,实现一个新的XMPPConnection与PacketWriter关联,那么老的代码维护起来是很巨大的,如果这里XMPPConnection和他的同事类PacketWriter都有相对应的接口,(XMPPConnection的接口是Connection)那就更完美了,而这里用到的模式应该是中介者,不是绝对意义的中介者,由于形成中介者的条件比较高,所以实际开发中多是变形使用。PacketWriter对象在XMPPConnection中的connect方法中被初始化,它的最大作用是在其自身的内部创建了两个消息循环,其中一个用30s的heartbeats向服务器发送空白字符,保持长连接。而第二个循环则时刻从队列中主动取消息并发往服务器,而向外部提供的sendPacket方法则是向queue中添加消息,前面提到的循环机制都是在线程中工作,而消息的队列用的是ArrayBlockingQueue,这个无边界阻塞队列可以存放任何对象,这里存放的是Packet对象。

     1     public void sendPacket(Packet packet) {
     2         if (!done) {
     3             try {
     4                 queue.put(packet);
     5             }
     6             catch (InterruptedException ie) {
     7                 ie.printStackTrace();
     8                 return;
     9             }
    10             synchronized (queue) {
    11                 queue.notifyAll();
    12             }
    13         }
    14     }
     1  while (!done && (writerThread == thisThread)) {
     2                 Packet packet = nextPacket();
     3                 if (packet != null) {
     4                     synchronized (writer) {
     5                         writer.write(packet.toXML());
     6                         writer.flush();
     7                         // Keep track of the last time a stanza was sent to the server
     8                         lastActive = System.currentTimeMillis();
     9                     }
    10                 }
    11             }

    消息循环则是一个通过各种成员变量控制的while loop,第一行的nextPacket方法是向queue中获取Packet消息,并且通过weiter将包发出去,这样生产/消费的模型就搭建好了,这里需要注意的是,我删减了很多影响阅读的代码,并没有全部贴上。关于heartbeats循环其实也是一个在线程中运行的while loop,也是通过一些成员控制。wirter向服务端写了写什么?看下面的这个方法

     1 void openStream() throws IOException {
     2         StringBuilder stream = new StringBuilder();
     3         stream.append("<stream:stream");
     4         stream.append(" to=\"").append(connection.getServiceName()).append("\"");
     5         stream.append(" xmlns=\"jabber:client\"");
     6         stream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
     7         stream.append(" version=\"1.0\">");
     8         writer.write(stream.toString());
     9         writer.flush();
    10     }

    XML,没错,这也是符合XMPP协议规范的一种表现吧,至于更多XMPP协议的好处,由于本人的经验有限,就不多做点评,希望后续会对其深入了解。

    下面看一个PacketReader这个类都包含了什么职责。

  • 相关阅读:
    【MySQL】JavaWeb项目中配置数据库的连接池
    【Java】Struts2配置默认Action和配置Action的默认处理类
    【Java】Struts2中使用ServletAPI
    【JavaScript】JS对象-属性的遍历,删除对象属性
    nginx 的三种虚拟主机配置方法
    nginx官方源安装-主配置文件详解
    http协议工作原理及工作流程
    ssh安全优化免密登陆
    sersync 实时同步网站数据
    nfs 共享存储
  • 原文地址:https://www.cnblogs.com/rioder/p/2873176.html
Copyright © 2011-2022 走看看