现在的位置: 首页 > 综合 > 正文

android socket nio 聊天实现

2018年04月05日 ⁄ 综合 ⁄ 共 4754字 ⁄ 字号 评论关闭
用nio代替传统io 实现socket.

代码实现如下(未完善):
package com.boyaa.push.lib.service;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.ArrayList;
import java.util.Iterator;

import android.content.Context;
import android.util.Log;

/**
 * 
 * @author Administrator
 *
 */
public class NioClient {
	
	private final int STATE_OPEN=1;//socket打开
	private final int STATE_CLOSE=1<<1;//socket关闭
	private final int STATE_CONNECT_START=1<<2;//开始连接server
	private final int STATE_CONNECT_SUCCESS=1<<3;//连接成功
	
	private String IP="192.168.1.101";
	private int PORT=60000;
	private int state=STATE_CONNECT_START;
	
	Selector selector;
	ByteBuffer readBuffer = ByteBuffer.allocate(8192);
	SocketChannel socketChannel;
	
	private Thread conn=null;
	private Thread rec=null;
	
	private Context context;
	private ISocketResponse respListener;
	private ArrayList<Packet> requestQueen=new ArrayList<Packet>();
	private final Object lock=new Object();
	private final String TAG="NioClient";
	
	public int send(Packet in)
	{
		synchronized (lock) 
		{
			requestQueen.add(in);
		}
		this.selector.wakeup();
		return in.getId();
	}
	
	public void cancel(int reqId)
	{
		 Iterator<Packet> mIterator=requestQueen.iterator();
		 while (mIterator.hasNext()) 
		 {
			 Packet packet=mIterator.next();
			 if(packet.getId()==reqId)
			 {
				 mIterator.remove();
			 }
		}
	}
	
	public NioClient(Context context,ISocketResponse respListener)
	{
		this.context=context;
		this.respListener=respListener;
	}
	
	public boolean isSocketConnected()
	{
		return ((state==STATE_CONNECT_SUCCESS)&&(null!=rec&&rec.isAlive()));
	}
	
	public void open()
	{
		reconn();
	}
	
	public void open(String host,int port)
	{
		this.IP=host;
		this.PORT=port;
		reconn();
	}
	
	private long lastConnTime=0;
	public synchronized void reconn()
	{
		if(System.currentTimeMillis()-lastConnTime<2000)
		{
			return;
		}
		lastConnTime=System.currentTimeMillis();
		
		close();
		state=STATE_OPEN;
		conn=new Thread(new Conn());
		conn.start();
	}
	
	public synchronized void close()
	{
		try {
			if(state!=STATE_CLOSE)
			{
				try {
					if(null!=conn&&conn.isAlive())
					{
						conn.interrupt();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}finally{
					conn=null;
				}
				
				try {
					if(null!=rec&&rec.isAlive())
					{
						rec.interrupt();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}finally{
					rec=null;
				}
				
				state=STATE_CLOSE;
			}
			requestQueen.clear();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private class Conn implements Runnable
	{
		public void run() {
Log.v(TAG,"Conn :Start");

			try {
					state=STATE_CONNECT_START;
					
					selector=SelectorProvider.provider().openSelector();
					socketChannel = SocketChannel.open();
					socketChannel.configureBlocking(false);
					
					InetSocketAddress address=new InetSocketAddress(IP, PORT);
					socketChannel.connect(address);
					socketChannel.register(selector, SelectionKey.OP_CONNECT);
				
					while(state!=STATE_CLOSE)
					{
Log.v(TAG,"Conn :-------");
								selector.select();
								Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
								while (selectedKeys.hasNext())
								{
									SelectionKey key = (SelectionKey) selectedKeys.next();
									selectedKeys.remove();

									if (!key.isValid())
									{
										continue;
									}

									if (key.isConnectable()) 
									{
										finishConnection(key);
									} 
									else if (key.isReadable()) 
									{
										read(key);
									} 
									else if (key.isWritable())
									{
										write(key);
									}
								}
								
								synchronized(lock)
								{
									if(requestQueen.size()>0)
									{
										SelectionKey  key=socketChannel.keyFor(selector);
										key.interestOps(SelectionKey.OP_WRITE);
									}
								}
					}
					
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				if(null!=socketChannel)
				{
					socketChannel.keyFor(selector).cancel();
					try {
						socketChannel.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
			}
Log.v(TAG,"Conn :End");
		}
		
		
		private boolean finishConnection(SelectionKey key) throws IOException 
		{
			boolean result=false;
			SocketChannel socketChannel = (SocketChannel) key.channel();
			result= socketChannel.finishConnect();//没有网络的时候也返回true
			if(result)
			{
				key.interestOps(SelectionKey.OP_READ);
				state=STATE_CONNECT_SUCCESS;
			}
Log.v(TAG,"finishConnection :"+result);
			return result;
		}
		
		
		private void read(SelectionKey key) throws IOException 
		{
			SocketChannel socketChannel = (SocketChannel) key.channel();
			readBuffer.clear();
			int numRead;
			numRead = socketChannel.read(readBuffer);
			if (numRead == -1) 
			{
				key.channel().close();
				key.cancel();
				return;
			}
respListener.onSocketResponse(new String(readBuffer.array(), 0, numRead));
		}
		
		private void write(SelectionKey key) throws IOException 
		{
			SocketChannel socketChannel = (SocketChannel) key.channel();
			synchronized (lock) 
			{
				 Packet item;
				 Iterator<Packet> iter=requestQueen.iterator();
				 while(iter.hasNext())
				 {
					 item=iter.next();
					 ByteBuffer buf=ByteBuffer.wrap(item.getPacket());
					 socketChannel.write(buf);
					 iter.remove();
				 }
				 item=null;
			}
			key.interestOps(SelectionKey.OP_READ);
		}
	}
}

完整代码参照:github: https://github.com/zz7zz7zz/android-socket-nio

csdn: http://download.csdn.net/detail/zz7zz7zz/6009821

nio基础知识文章:

http://blog.csdn.net/zz7zz7zz/article/details/9673105

https://github.com/viveksri15/nio

https://github.com/astutesparrow/nio

https://github.com/XUbiker/NIO_Chat

http://developer.51cto.com/art/201112/307172.htm

http://rox-xmlrpc.sourceforge.net/niotut/index.html

邮箱:zz7zz7zz@163.com

微博http://weibo.com/u/3209971935

抱歉!评论已关闭.