smack 源码分析- PacketWriter (android上实现长连接)【2】

来源:互联网 发布:禁止王者荣耀端口 编辑:程序博客网 时间:2024/04/30 09:16

上一篇smack 源码分析一(android上实现长连接)  整体分析了smack长连接的流程, 本篇将详细介绍PacketWriter.

PacketWriter是在上篇在介绍initConnection()方法中创建的,那么详细看下PacketWriter的实现:


[java] view plaincopy
  1. protected PacketWriter(XMPPConnection connection) {  
  2.         this.queue = new ArrayBlockingQueue<Packet>(500true);  
  3.         this.connection = connection;  
  4.         init();  
  5.  }  
  6.   
  7.   
  8.   
  9.   
  10. protected void init() {  
  11.         this.writer = connection.writer;  
  12.         done = false;  
  13.         lastActive = System.currentTimeMillis();  
  14.           
  15.         //开辟一个写网络流数据线程  
  16.         writerThread = new Thread() {  
  17.             public void run() {  
  18.                 writePackets(this);  
  19.             }  
  20.         };  
  21.   
  22.         writerThread.setName("Smack Packet Writer (" + connection.connectionCounterValue + ")");  
  23.         writerThread.setDaemon(true);  
  24.   
  25.     }  
  26.   
  27.   
  28.   
  29. /** 
  30.      * 向网络流写数据包 
  31.      * @param thisThread 
  32.      */  
  33.     private void writePackets(Thread thisThread) {  
  34.         try {  
  35.             // Open the stream.  
  36.             openStream();  
  37.             // Write out packets from the queue.  
  38.             while (!done && (writerThread == thisThread)) {  
  39.                 Packet packet = nextPacket();  
  40.                 if (packet != null) {  
  41.                     synchronized (writer) {  
  42.                         writer.write(packet.toXML());  
  43.                         writer.flush();  
  44.                         // Keep track of the last time a stanza was sent to the  
  45.                         // server  
  46.                         lastActive = System.currentTimeMillis();  
  47.                     }  
  48.                 }  
  49.             }  
  50.   
  51.             synchronized (writer) {  
  52.                 while (!queue.isEmpty()) {  
  53.                     Packet packet = queue.remove();  
  54.                     writer.write(packet.toXML());  
  55.                 }  
  56.                 writer.flush();  
  57.             }  
  58.   
  59.             queue.clear();  
  60.             writer.write("</stream:stream>");  
  61.             writer.flush();  
  62.   
  63.         } catch (IOException ioe) {  
  64.             if (!done) {  
  65.                 done = true;  
  66.                 connection.packetReader.notifyConnectionError(ioe);  
  67.             }  
  68.         } finally {  
  69.             try {  
  70.                 if (writer != null) {  
  71.                     writer.close();  
  72.                 }  
  73.             } catch (Exception e) {  
  74.             }  
  75.         }  
  76.     }  

在PacketWriter构造方法中传递参数XMPPConnection作为PacketWriter成员变量, 然后调用init()方法 ,而在init()方法中, 开辟一个线程专门用于向服务器写数据. writerPackets()里面是一个无限循环体, 不断的从消息队列queue读取pakcet消息读取完之后调用wirter.flush()方法, 将消息发送的服务器. 这个过程就完成了终端完服务器发送消息的过程. 


接下来是, 终端如何与云端保持连接呢, 那肯定是发送心跳包咯. 我们来看下PacketWriter是如何发送心跳包的:

   
[java] view plaincopy
  1. /** 
  2.      * A TimerTask that keeps connections to the server alive by sending a space 
  3.      * character on an interval. 
  4.      */  
  5.     private class KeepAliveTask implements Runnable {  
  6.   
  7.         private int delay;  
  8.         private Thread thread;  
  9.   
  10.         public KeepAliveTask(int delay) {  
  11.             this.delay = delay;  
  12.         }  
  13.   
  14.         protected void setThread(Thread thread) {  
  15.             this.thread = thread;  
  16.         }  
  17.           
  18.         public void run() {  
  19.             try {  
  20.                 // Sleep 15 seconds before sending first heartbeat. This will give time to  
  21.                 // properly finish TLS negotiation and then start sending heartbeats.  
  22.                 Thread.sleep(15000);  
  23.             }  
  24.             catch (InterruptedException ie) {  
  25.                 // Do nothing  
  26.             }  
  27.             while (!done && keepAliveThread == thread) {  
  28.                 synchronized (writer) {  
  29.                     // Send heartbeat if no packet has been sent to the server for a given time  
  30.                     if (System.currentTimeMillis() - lastActive >= delay) {  
  31.                         try {  
  32.                             writer.write(" ");  
  33.                             writer.flush();  
  34.                         }  
  35.                         catch (Exception e) {  
  36.                             // Do nothing  
  37.                         }  
  38.                     }  
  39.                 }  
  40.                 try {  
  41.                     // Sleep until we should write the next keep-alive.  
  42.                     Thread.sleep(delay);  
  43.                 }  
  44.                 catch (InterruptedException ie) {  
  45.                     // Do nothing  
  46.                 }  
  47.             }  
  48.         }  
  49.     }  

心跳发送类: KeepAliveTask 是一个自定义线程, 它定义了心跳发送的时间间隔, 在其run方法里面一个无限循环体每隔delay毫秒就向云端发发送一个空消息(当然, 如需要你可以根据项目需求自定义一个心跳包). 整个PacketWriter介绍基本到此结束, 在你应用登陆成功之后就可以开启KeepAliveTask 线程定时发送心跳包到服务器保持终端与服务器的长连接.