android中非阻塞socket通信

来源:互联网 发布:飞流 蔺晨 知乎 编辑:程序博客网 时间:2024/04/28 12:33

1、什么是同步与异步,阻塞与非阻塞

首先我们要明白搞明白:同步就等于阻塞?异步就等于非阻塞?这是不对的,同步不等于阻 塞,而异步也不等于非阻塞。

1)那什么是同步编程?

什么是同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。根据这个定义,android中绝大多数函数都是同步调用。但是一般而言,我们在谈论同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。在android中,由于主线程(UI线程的不安全性),我们经常会用到handler的SendMessage函数,就是一个同步线程,它将数据传送给某个窗口后,在对方处理完消息后,这个函数是不会返回的,当处理完毕的时候才返回相应的返回值。

2)那什么是异步编程?

异步的概念和同步相反的。当一个调用者异步发出一个功能调用时,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以 android中AsyncTask类为例,顾名思义异步执行任务,在doInBackground 执行完成后,onPostExecute 方法将被UI 线程调用,后台的计算结果将通过该方法传递到UI 线程,并且在界面上展示给用户.。在android或者java异步编程中需要注意以下几个知识点:回调,监听者模式,观察者模式。这几点在之后另外几篇文章中会提及。

3)什么是阻塞式编程?

阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在 得到结果之后才会返回。因为这点定义跟同步编程的定义很相像,所以很多人认为同步编程就等阻塞式编程。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。例如,我们在 socket编程中调用Receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消 息。如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。但是在android中,由于主线程(UI线程)的不安全性,特别到4.0版本后,系统已经不允许在主线程中进行耗时的同步编程。所以android才出现了AsyncTask类用于异步编程。

4)什么是非阻塞式编程?

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。从这个定义上来说,非阻塞编程可以说是异步编程的一种,但是异步编程并不等于非阻塞式编程。

5)区别大概

我们用买票的案例去理解它,当我们去买票的时候,如果还在排队,一直排着,直到买到票再离开,这个就是同步编程(所谓同步就是当一个进程发起一个函数(任务)调用的时候,一直会到函数(任务)完成)。那还有另外一方式,你可以叫一个人(监听者,观察者)帮你看着,直接你买票了,再通知你,你可以先去别的事情(而异步这不会这样,异步情况下是当一个进程发 起一个函数(任务)调用的时候,不会等函数返回)。阻塞是就是等排队,非阻塞就是直接走开。

2、几个关键知识点

1)java.net.InetSocketAddress

此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对(主机名 + 端口号),在此情况下,将尝试解析主机名。如果解析失败,则该地址将被视为未解析 地址,但是其在某些情形下仍然可以使用,比如通过代理连接。
需注意接口:
public InetSocketAddress(InetAddress addr,int port)
根据 IP 地址和端口号创建套接字地址。
有效端口值介于 0 和 65535 之间。端口号 zero 允许系统在 bind 操作中挑选暂时的端口。

2)java.nio.channels.Selector

可通过调用此类的 open 方法创建选择器,该方法将使用系统的默认选择器提供者创建新的选择器。也可通过调用自定义选择器提供者的 openSelector 方法来创建选择器。通过选择器的 close 方法关闭选择器之前,它一直保持打开状态。
需注意接口:
public static Selector open()throws IOException
打开一个选择器。
public abstract void close()throws IOException
关闭此选择器。
如果某个线程目前正阻塞在此选择器的某个选择方法中,则中断该线程,如同调用该选择器的 wakeup 方法那样。
所有仍与此选择器关联的未取消键已无效、其通道已注销,并且与此选择器关联的所有其他资源已释放。
如果此选择器已经关闭,则调用此方法无效。
关闭选择器后,除了调用此方法或 wakeup 方法外,以任何其他方式继续使用它都将导致抛出 ClosedSelectorException。
注:选择器的关闭是关键点,特别需要注意上述第二条

3)java.nio.channels.SocketChannel

针对面向流的连接套接字的可选择通道。
套接字通道不是连接网络套接字的完整抽象。必须通过调用 socket 方法所获得的关联 Socket 对象来完成对套接字选项的绑定、关闭和操作。不可能为任意的已有套接字创建通道,也不可能指定与套接字通道关联的套接字所使用的 SocketImpl 对象。

通过调用此类的某个 open 方法创建套接字通道。新创建的套接字通道已打开,但尚未连接。试图在未连接的通道上调用 I/O 操作将导致抛出 NotYetConnectedException。可通过调用套接字通道的 connect 方法连接该通道;一旦连接后,关闭套接字通道之前它会一直保持已连接状态。可通过调用套接字通道的 isConnected 方法来确定套接字通道是否已连接。

套接字通道支持非阻塞连接:可创建一个套接字通道,并且通过 connect 方法可以发起到远程套接字的连接,之后通过 finishConnect 方法完成该连接。可通过调用 isConnectionPending 方法来确定是否正在进行连接操作。

可单独地关闭 套接字通道的输入端和输出端,而无需实际关闭该通道。调用关联套接字对象的 shutdownInput 方法来关闭某个通道的输入端将导致该通道上的后续读取操作返回 -1(指示流的末尾)。调用关联套接字对象的 shutdownOutput 方法来关闭通道的输出端将导致该通道上的后续写入操作抛出 ClosedChannelException。

套接字通道支持异步关闭,这与 Channel 类中所指定的异步 close 操作类似。如果一个线程关闭了某个套接字的输入端,而同时另一个线程被阻塞在该套接字通道上的读取操作中,那么处于阻塞线程中的读取操作将完成,而不读取任何字节且返回 -1。I如果一个线程关闭了某个套接字的输出端,而同时另一个线程被阻塞在该套接字通道上的写入操作中,那么阻塞线程将收到 AsynchronousCloseException。

多个并发线程可安全地使用套接字通道。尽管在任意给定时刻最多只能有一个线程进行读取和写入操作,但数据报通道支持并发的读写。connect 和 finishConnect 方法是相互同步的,如果正在调用其中某个方法的同时试图发起读取或写入操作,则在该调用完成之前该操作被阻塞。

3、实例代码演示

连接核心代码:

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. Selector mSelector = null;  
  2. ByteBuffer sendBuffer = null;  
  3. SocketChannel client = null;  
  4. InetSocketAddress isa = null;  
  5. SocketEventListener mSocketEventListener = null;  
  6. private boolean Connect(String site, int port)  
  7. {  
  8.         if (mSocketEventListener != null)  
  9.         {  
  10.                 mSocketEventListener.OnSocketPause();  
  11.         }  
  12.         boolean ret = false;  
  13.         try  
  14.         {  
  15.                 mSelector = Selector.open();  
  16.                 client = SocketChannel.open();  
  17.                 client.socket().setSoTimeout(5000);  
  18.                 isa = new InetSocketAddress(site, port);  
  19.                 boolean isconnect = client.connect(isa);  
  20.                 // 将客户端设定为异步  
  21.                 client.configureBlocking(false);  
  22.                 // 在轮讯对象中注册此客户端的读取事件(就是当服务器向此客户端发送数据的时候)  
  23.                 client.register(mSelector, SelectionKey.OP_READ);  
  24.                   
  25.                 long waittimes = 0;  
  26.   
  27.                 if(!isconnect)  
  28.                 {  
  29.                     while (!client.finishConnect())  
  30.                     {  
  31.                             EngineLog.redLog(TAG,  "等待非阻塞连接建立....");  
  32.                             Thread.sleep(50);  
  33.                             if(waittimes < 100)  
  34.                             {  
  35.                                     waittimes++;  
  36.                             }  
  37.                             else  
  38.                             {  
  39.                                     break;  
  40.                             }  
  41.                     }  
  42.                 }  
  43.                 Thread.sleep(500);  
  44.                 haverepaired();  
  45.                 startListener();  
  46.                 ret = true;  
  47.         }  
  48.         catch (Exception e)  
  49.         {  
  50.                 EngineLog.redLog(TAG + " - Connect error", e != null ? e.toString() : "null");  
  51.                 try  
  52.                 {  
  53.                         Thread.sleep(1000 * 10);  
  54.                 }  
  55.                 catch (Exception e1)  
  56.                 {  
  57.                         EngineLog.redLog(TAG + " - Connect error", e1 != null ? e1.toString() : "null");  
  58.                 }  
  59.                 ret = false;  
  60.         }  
  61.         return ret;  
  62. }  
在上述代码中,我们可以看到有一个SocketEventListener监听接口,这个接口用于监听socket事件,将其回调给调用者
SocketEventListener接口:
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public interface SocketEventListener  
  2.         {  
  3.                 /** 
  4.                  * Socket正在接收数据 
  5.                  * */  
  6.                 public void OnStreamRecive();  
  7.                 /** 
  8.                  * Socket接收数据完成 
  9.                  * */  
  10.                 public void OnStreamReciveFinish();  
  11.                 /** 
  12.                  * Socket有新的消息返回 
  13.                  * */  
  14.                 public void OnStreamComing(byte[] aStreamData);  
  15.                 /** 
  16.                  * Socket出现异常 
  17.                  * */  
  18.                 public void OnSocketPause();  
  19.                 /** 
  20.                  * Socket已修复,可用 
  21.                  * */  
  22.                 public void OnSocketAvaliable();  
  23.         }  
监听接口的使用:
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. rivate void startListener()  
  2.         {  
  3.                 if (mReadThread == null || mReadThread.isInterrupted())  
  4.                 {  
  5.                         mReadThread = null;  
  6.                         mReadThread = new Thread()  
  7.                         {  
  8.                                 @Override  
  9.                                 public void run()  
  10.                                 {  
  11.                                         while (!this.isInterrupted() && mRunRead)  
  12.                                         {  
  13.                                                 MyLineLog.redLog(TAG,"startListener:" + mSendMsgTime);  
  14.                                                 try  
  15.                                                 {  
  16.                                                      // 如果客户端连接没有打开就退出循环  
  17.                                                         if (!client.isOpen())  
  18.                                                                 break;  
  19.                                                         // 此方法为查询是否有事件发生如果没有就阻塞,有的话返回事件数量  
  20.                                                         int eventcount = mSelector.select();  
  21.                                                         // 如果没有事件返回循环  
  22.                                                         if (eventcount > 0)  
  23.                                                         {  
  24.                                                             starttime = CommonClass.getCurrentTime();  
  25.                                                                 // 遍例所有的事件  
  26.                                                                 for (SelectionKey key : mSelector.selectedKeys())  
  27.                                                                 {  
  28.                                                                         // 删除本次事件  
  29.                                                                         mSelector.selectedKeys().remove(key);  
  30.                                                                         // 如果本事件的类型为read时,表示服务器向本客户端发送了数据  
  31.                                                                         if (key.isValid() && key.isReadable())  
  32.                                                                         {  
  33.                                                                                 if (mSocketEventListener != null)  
  34.                                                                                 {  
  35.                                                                                         mSocketEventListener.OnStreamRecive();  
  36.                                                                                 }  
  37.                                                                                 boolean readresult = ReceiveDataBuffer((SocketChannel) key.channel());  
  38.   
  39.                                                                                 if (mSocketEventListener != null)  
  40.                                                                                 {  
  41.                                                                                         mSocketEventListener.OnStreamReciveFinish();  
  42.                                                                                 }  
  43.                                                                                   
  44.                                                                                 if(readresult)  
  45.                                                                                 {  
  46.                                                                                         key.interestOps(SelectionKey.OP_READ);  
  47.                                                                                         sleep(200);  
  48.                                                                                 }  
  49.                                                                                 else  
  50.                                                                                 {  
  51.                                                                                         throw new Exception();  
  52.                                                                                 }  
  53.                                                                         }  
  54.                                                                         key = null;  
  55.                                                                 }  
  56.                                                                 mSelector.selectedKeys().clear();  
  57.                                                         }  
  58.                                                 }  
  59.                                                 catch (Exception e)  
  60.                                                 {  
  61.                                                         mRunRead = false;  
  62.                                                         mReadThread = null;  
  63.                                                         if(e instanceof InterruptedException)  
  64.                                                         {  
  65.                                                                 MyLineLog.redLog(TAG, "startListener:" + e.toString());  
  66.                                                         }  
  67.                                                         else  
  68.                                                         {  
  69.                                                                 break;  
  70.                                                         }  
  71.                                                 }  
  72.                                         }  
  73.                                 }  
  74.                         };  
  75.                         mReadThread.setName(TAG + " Listener, " + CommonClass.getCurrentTime());  
  76.                         mRunRead = true;  
  77.                         mReadThread.start();  
  78.                 }  
  79.         }  

连接完之后就是发送数据和接收数据,下面是发送数据的核心代码:

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public boolean SendSocketMsg(byte[] aMessage) throws IOException  
  2.         {  
  3.                 boolean ret = false;  
  4.                 try  
  5.                 {  
  6.                         sendBuffer.clear();  
  7.                         sendBuffer = ByteBuffer.wrap(aMessage);  
  8.                         int sendsize = client.write(sendBuffer);  
  9.                         sendBuffer.flip();  
  10.                         sendBuffer.clear();  
  11.                         mSendMsgTime = CommonClass.getCurrentTime();  
  12.                         MyLineLog.redLog(TAG, "SendSocketMsg:" + mSendMsgTime + ", sendsize:" + sendsize);  
  13.                         ret = true;  
  14.                 }  
  15.                 catch (Exception e)  
  16.                 {  
  17.                         MyLineLog.redLog(TAG,  "发送数据失败。");  
  18.   
  19.                         if (mSocketEventListener != null)  
  20.                         {  
  21.                                 mSocketEventListener.OnSocketPause();  
  22.                         }  
  23. //                        crash();  
  24.                 }  
  25.                 return ret;  
  26.         }  

因为实际工作需要,我们需要经常会碰到两个问题,无效数据和大数据,如何去解决这个问题呢,无效数据用过滤,大数据用分块接收,下面是接收数据的方法:
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. private boolean ReceiveDataBuffer(SocketChannel aSocketChannel)  
  2.         {  
  3. //              n 有数据的时候返回读取到的字节数。  
  4. //              0 没有数据并且没有达到流的末端时返回0。  
  5. //              -1 当达到流末端的时候返回-1。  
  6.                 boolean ret = false;  
  7.                   
  8.                 ByteArrayBuffer bab = new ByteArrayBuffer(8*1024);  
  9.                 while(true)  
  10.                 {  
  11.                         try  
  12.                         {  
  13.                                 ByteBuffer readBuffer = ByteBuffer.allocate(1024 * 1);  
  14.                                 readBuffer.clear();  
  15.                                 int readsize = aSocketChannel.read(readBuffer);  
  16.                                   
  17.                                 if(readsize > 0)  
  18.                                 {  
  19.                                     MyLineLog.redLog(TAG, "aSocketChannel.read=>" + readsize);  
  20.                                         byte[] readbytes = readBuffer.array();  
  21.                                         bab.append(readbytes, 0, readsize);  
  22.                                         readBuffer.clear();  
  23.                                         readBuffer.flip();  
  24.                                         ret = true;  
  25.                                 }  
  26.                                 else if(readsize == 0)  
  27.                                 {  
  28.                                         int buffersize = bab.length();                                          
  29.                                         byte[] readdata = bab.buffer();  
  30.                                         int readdataoffset = 0;  
  31.                                         boolean parsedata = true;  
  32.                                           
  33.                                         while(readdataoffset < buffersize && parsedata)  
  34.                                         {  
  35.                                                 byte datatype = readdata[readdataoffset];  
  36.                                                 if (datatype == PushUtils.PACKAGETYPE_HEARTBEAT || datatype == PushUtils.PACKAGETYPE_HEARTBEAR_NODATA)  
  37.                                                 {  
  38.                                                         byte[] blockdata = new byte[] { datatype };  
  39.                                                         ReceiveData(blockdata);  
  40.                                                         readdataoffset += 1;  
  41.                                                         blockdata = null;              
  42.                                                 }  
  43.                                                 else  
  44.                                                 {  
  45.                                                         byte[] blocklength = new byte[4];  
  46.                                                         System.arraycopy(readdata, readdataoffset + 5, blocklength, 04);  
  47.                                                         int blocksize = CommonClass.bytes2int(CommonClass.LitteEndian_BigEndian(blocklength));  
  48.                                                         blocklength = null;  
  49.                                                           
  50.                                                         int blockdatasize = 5 + blocksize + 4;  
  51.                                                           
  52.                                                         if(blockdatasize <= buffersize)  
  53.                                                         {  
  54.                                                                 MyLineLog.redLog(TAG, "块数据大小:" + blockdatasize);  
  55.                                                                 byte[] blockdata = new byte[blockdatasize];  
  56.                                                                 System.arraycopy(readdata, readdataoffset, blockdata, 0, blockdatasize);  
  57.   
  58.                                                                 long starttime = CommonClass.getCurrentTime();  
  59.                                                                 ReceiveData(blockdata);  
  60.                                                                 long endtime = CommonClass.getCurrentTime();  
  61.                                                                 MyLineLog.redLog(TAG, "解析数据用时:" + (endtime - starttime) + "ms");  
  62.                                                                 readdataoffset += blockdatasize;  
  63.                                                                 blockdata = null;  
  64.                                                         }  
  65.                                                         else if(blockdatasize < 10240)  
  66.                                                         {//小于10k,则属于正常包  
  67.                                                                 MyLineLog.redLog(TAG, "块数据大小:" + blockdatasize + ",小于10k,说明数据不完整,继续获取。");  
  68.                                                                 //将未解析数据存到临时buffer  
  69.                                                                 int IncompleteSize = buffersize - readdataoffset;  
  70.                                                                 if(IncompleteSize > 0)  
  71.                                                                 {  
  72.                                                                         byte[] Incompletedata = new byte[IncompleteSize];  
  73.                                                                         System.arraycopy(readdata, readdataoffset, Incompletedata, 0, IncompleteSize);  
  74.                                                                         bab.clear();  
  75.                                                                         bab.append(Incompletedata, 0, IncompleteSize);  
  76.                                                                         parsedata = false;  
  77.                                                                         Incompletedata = null;  
  78.                                                                 }  
  79.                                                         }  
  80.                                                         else  
  81.                                                         {//异常包  
  82.                                                                 MyLineLog.yellowLog(TAG, "块数据错误大小:" + blockdatasize);  
  83.                                                                 MyLineLog.redLog(TAG,"blockdatasize error:" + blockdatasize);  
  84.                                                                 ret = true;  
  85.                                                                 break;  
  86.                                                         }  
  87.                                                 }  
  88.                                         }    
  89.                                           
  90.                                         if(parsedata)  
  91.                                         {  
  92.                                                 ret = true;  
  93.                                                 break;  
  94.                                         }  
  95.                                 }  
  96.                                 else if(readsize == -1)  
  97.                                 {  
  98.                                         ret = false;  
  99.                                         break;  
  100.                                 }  
  101.                                 else  
  102.                                 {  
  103.                                         ret = true;  
  104.                                         break;  
  105.                                 }  
  106.                         }  
  107.                         catch (IOException e)  
  108.                         {  
  109.                             MyLineLog.redLog(TAG, "aSocketChannel IOException=>" + e.toString());  
  110.                                 ret = false;  
  111.                                 break;  
  112.                         }  
  113.                 }  
  114.                 bab.clear();  
  115.                 bab = null;  
  116.                 return ret;  
  117.         }  

如果数据量过大的话,还会使用压缩方法进行传输,那应该如何接收呢,下面是一段接收压缩数据的方法:
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. private void ReceiveData(byte[] aDataBlock)  
  2.         {  
  3.                 try  
  4.                 {  
  5.                         MyLineLog.redLog(TAG, "ReceiveData:" + mSendMsgTime);  
  6.                         if (mSendMsgTime != 0)  
  7.                         {  
  8.                                 mSendMsgTime = 0;  
  9.                         }  
  10.                           
  11.                         byte[] ret = null;  
  12.                           
  13.                         int offset = 0;  
  14.   
  15.                         byte datatype = aDataBlock[offset];  
  16.                         offset += 1;  
  17.   
  18.                         if (datatype != -1)  
  19.                         {  
  20.                                 if (datatype == PushUtils.PACKAGETYPE_HEARTBEAT)  
  21.                                 {  
  22.                                         ret = new byte[] { datatype };  
  23.                                 }  
  24.                                 else if (datatype == PushUtils.PACKAGETYPE_HEARTBEAR_NODATA)  
  25.                                 {  
  26.                                         ret = new byte[] { datatype };  
  27.                                 }  
  28.                                 else if (datatype == PushUtils.PACKAGETYPE_NORMAL || datatype == PushUtils.PACKAGETYPE_HEARTBEAR_HAVEDATA)  
  29.                                 {  
  30.                                         byte[] databytelength = new byte[4];  
  31.                                         System.arraycopy(aDataBlock, offset, databytelength, 04);  
  32.                                         offset += 4;  
  33.                                         int header = CommonClass.bytes2int(CommonClass.LitteEndian_BigEndian(databytelength));  
  34.                                         databytelength = null;  
  35.   
  36.                                         if (header == PushUtils.PACKAGEHEADER)  
  37.                                         {  
  38.                                                 byte[] datalengthbyte = new byte[4];  
  39.                                                 System.arraycopy(aDataBlock, offset, datalengthbyte, 04);  
  40.                                                 offset += 4;  
  41.   
  42.                                                 int datalength = CommonClass.bytes2int(CommonClass.LitteEndian_BigEndian(datalengthbyte));  
  43.                                                 datalengthbyte = null;  
  44.   
  45.                                                 if (datalength > 4)  
  46.                                                 {  
  47.                                                         // compressed bit 暂时不压缩  
  48.                                                         byte compressed = aDataBlock[offset];  
  49.                                                         offset += 1;  
  50.   
  51.                                                         if (compressed == 1)  
  52.                                                         {//解压缩  
  53.                                                                 //跳过头4个字节,此处用于解压缩后的数据大小,暂时不需要  
  54.                                                                 offset += 4;  
  55.                                                                 int contentlength = datalength - 1 - 4;  
  56.                                                                 byte[] datacontentbyte = new byte[contentlength];  
  57.                                                                 System.arraycopy(aDataBlock, offset, datacontentbyte, 0, contentlength);  
  58.                                                                 offset += contentlength;                                                                 
  59.   
  60.                                                                 byte[] compressdata = new byte[contentlength - 4];  
  61.                                                                 System.arraycopy(datacontentbyte, 0, compressdata, 0, contentlength - 4);  
  62.   
  63.                                                                 long starttime = CommonClass.getCurrentTime();  
  64.                                                                 byte[] decompressdatacontentbyte = CommonClass.decompress(compressdata);  
  65.                                                                 long endtime = CommonClass.getCurrentTime();  
  66.                                                                 MyLineLog.redLog(TAG, "解压缩数据用时:" + (endtime - starttime) + "ms");  
  67.                                                                 int decompressdatacontentbytelength = decompressdatacontentbyte.length;  
  68.                                                                 compressdata = null;  
  69.                                                                 int footer = PushUtils.getInt(datacontentbyte, contentlength - 4);  
  70.   
  71.                                                                 if (footer == PushUtils.PACKAGEFOOTER)  
  72.                                                                 {  
  73.                                                                         ret = new byte[decompressdatacontentbytelength + 1];  
  74.                                                                         ret[0] = datatype;  
  75.                                                                         System.arraycopy(decompressdatacontentbyte, 0, ret, 1, decompressdatacontentbytelength);  
  76.                                                                         datacontentbyte = null;  
  77.                                                                         decompressdatacontentbyte = null;  
  78.                                                                 }  
  79.                                                         }  
  80.                                                         else  
  81.                                                         {//数据未压缩  
  82.                                                                 int contentlength = datalength - 1;  
  83.                                                                 byte[] datacontentbyte = new byte[contentlength];  
  84.                                                                 System.arraycopy(aDataBlock, offset, datacontentbyte, 0, contentlength);  
  85.                                                                 offset += contentlength;  
  86.   
  87.                                                                 int footer = PushUtils.getInt(datacontentbyte, contentlength - 4);  
  88.   
  89.                                                                 if (footer == PushUtils.PACKAGEFOOTER)  
  90.                                                                 {  
  91.                                                                         ret = new byte[contentlength + 1 - 4];  
  92.                                                                         ret[0] = datatype;  
  93.                                                                         System.arraycopy(datacontentbyte, 0, ret, 1, contentlength - 4);  
  94.                                                                         datacontentbyte = null;  
  95.                                                                 }                                                                  
  96.                                                         }  
  97.                                                 }  
  98.                                         }  
  99.                                 }  
  100.   
  101.                                 if (mSocketEventListener != null)  
  102.                                 {  
  103.                                         mSocketEventListener.OnStreamComing(ret);  
  104.                                 }  
  105.                         }   
  106.                 }  
  107.                 catch (Exception e)  
  108.                 {  
  109.                         MyLineLog.redLog(TAG + " - ReceiveData error", e.toString());  
  110.                 }  
  111.         }  

在介绍SocketChannel的时候,api提到关闭需要注意事项,下面一段关闭SocketChannel的示例代码:
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public void closeSocket()  
  2.         {  
  3.                 mRunRead = false;  
  4.                 if (mReadThread != null)  
  5.                 {  
  6.                         if (!mReadThread.isInterrupted())  
  7.                         {  
  8.                                 mReadThread.interrupt();  
  9.                                 mReadThread = null;  
  10.                         }  
  11.                 }  
  12.   
  13.                 if (mSelector != null && mSelector.isOpen())  
  14.                 {  
  15.                         try  
  16.                         {  
  17.                                 mSelector.close();  
  18.                         }  
  19.                         catch (IOException e)  
  20.                         {  
  21.                                 MyLineLog.redLog(TAG + " - closeSocket error", e.toString());  
  22.                         }  
  23.                         mSelector = null;  
  24.                 }  
  25.                   
  26.                 if (client != null)  
  27.                 {  
  28.                         try  
  29.                         {  
  30.                                 client.close();  
  31.                                 client = null;  
  32.                         }  
  33.                         catch (IOException e)  
  34.                         {  
  35.                                 MyLineLog.redLog(TAG + " - closeSocket2 error", e.toString());  
  36.                         }  
  37.                 }  
  38.   
  39.                 System.gc();  
  40.         }  

这篇文章讲解部分大量参照JavaApi,其实很多问题的答案就在Api里面,当你不知道如何去做的时候,回头看一下Api,仔细思考一下,就能解决大部分问题。
0 0