android socket nio 聊天实现

用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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Web Socket 是一种用于实现浏览器与服务器全双工通信的协议,支持双向实时通信。在 Java 中实现 Web Socket 聊天可以使用 Java API for WebSocket(JSR-356)实现。 以下是一个简单的 Web Socket 聊天室的示例: 1. 创建一个聊天处理程序 ChatHandler,继承自 javax.websocket.Endpoint 和 javax.websocket.MessageHandler.Partial 接口: ``` import java.io.IOException; import java.nio.ByteBuffer; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.Session; public class ChatHandler extends Endpoint implements MessageHandler.Partial<String> { private Session session; @Override public void onOpen(Session session, EndpointConfig config) { this.session = session; session.addMessageHandler(this); } @Override public void onMessage(String message, boolean last) { try { // 发送消息给所有连接的客户端 for (Session s : session.getOpenSessions()) { if (s.isOpen()) { s.getBasicRemote().sendText(message, last); } } } catch (IOException e) { e.printStackTrace(); } } @Override public void onMessage(ByteBuffer message, boolean last) { throw new UnsupportedOperationException("Binary messages not supported."); } } ``` 2. 创建一个 WebSocket 端点 ChatEndpoint,继承自 javax.websocket.server.ServerEndpoint: ``` import javax.websocket.server.ServerEndpoint; @ServerEndpoint(value = "/chat", encoders = {MessageEncoder.class}, decoders = {MessageDecoder.class}) public class ChatEndpoint { // 该注解会自动创建 ChatHandler 实例,并将其添加到 WebSocket 会话中 } ``` 3. 创建一个消息编码器 MessageEncoder 和一个消息解码器 MessageDecoder,用于在客户端与服务器之间转换消息: ``` import javax.json.Json; import javax.json.JsonObject; import javax.websocket.EncodeException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; public class MessageEncoder implements Encoder.Text<Message> { @Override public String encode(Message message) throws EncodeException { JsonObject jsonObject = Json.createObjectBuilder() .add("sender", message.getSender()) .add("content", message.getContent()) .build(); return jsonObject.toString(); } @Override public void init(EndpointConfig config) {} @Override public void destroy() {} } ``` ``` import java.io.StringReader; import javax.json.Json; import javax.json.JsonObject; import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.EndpointConfig; public class MessageDecoder implements Decoder.Text<Message> { @Override public Message decode(String s) throws DecodeException { JsonObject jsonObject = Json.createReader(new StringReader(s)).readObject(); return new Message(jsonObject.getString("sender"), jsonObject.getString("content")); } @Override public boolean willDecode(String s) { try { Json.createReader(new StringReader(s)).readObject(); return true; } catch (Exception e) { return false; } } @Override public void init(EndpointConfig config) {} @Override public void destroy() {} } ``` 4. 创建一个消息类 Message,用于表示聊天消息: ``` public class Message { private String sender; private String content; public Message(String sender, String content) { this.sender = sender; this.content = content; } public String getSender() { return sender; } public void setSender(String sender) { this.sender = sender; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } ``` 5. 在 HTML 页面中使用 JavaScript 创建 WebSocket 连接并发送和接收消息: ``` <script> var websocket = new WebSocket("ws://localhost:8080/chat"); websocket.onopen = function(event) { console.log("WebSocket connected."); }; websocket.onmessage = function(event) { var message = JSON.parse(event.data); console.log("Received message: " + message.content); }; function sendMessage() { var message = document.getElementById("messageInput").value; websocket.send(JSON.stringify({sender: "user", content: message})); console.log("Sent message: " + message); } </script> ``` 6. 将 ChatEndpoint、ChatHandler、MessageEncoder、MessageDecoder 和 Message 类打包成一个 WAR 文件,并部署到 Tomcat 或 Jetty 中。 这样就可以在浏览器中访问 HTML 页面,通过 WebSocket 实现实时聊天了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值