SocketUtil.java

package com.lee.ademo.net;import java.io.ByteArrayOutputStream;import java.io.EOFException;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.util.Iterator;import java.util.Set;import com.lee.ademo.base.MLog;public class SocketUtil extends Thread {protected Selector selector = null;protected SocketChannel client = null;protected static final int CONNECT_TIMEOUT = 10000;protected static final int READ_TIMEOUT = 10000;protected static final int RECONNECT_TIME = 120000;protected static final int RECONNECT_TIME_SECOND = RECONNECT_TIME / 1000;protected final byte CONNECT = 1;protected final byte RUNNING = 2;protected byte STATE = CONNECT;protected boolean onWork;// 是否工作状态static {java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");};private static String ip = "127.0.0.1";private static int port = 9527;private ConnectListener connectListener;public static enum ENUM_CONNECT {STATUS_OK, STATUS_FAIL};public SocketUtil(String ip, int port) {SocketUtil.ip = ip;SocketUtil.port = port;onWork = true;}public boolean isReady() {return STATE == RUNNING;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (onWork) {switch (STATE) {case CONNECT:connect();break;case RUNNING:running();break;default:break;}}}private synchronized void running() {SelectionKey key = null;try {while (selector.select() > 0) {Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> iterator = keys.iterator();while (iterator.hasNext()) {key = iterator.next();iterator.remove();byte[] data = readBuf(key);if (data != null)MLog.makeText(new String(data));}}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();closeKey(key);}}private final byte[] readBuf(SelectionKey selectionKey) throws IOException {if (selectionKey.isReadable()) {SocketChannel client = (SocketChannel) selectionKey.channel();// 如果缓冲区过小的话那么信息流会分成多次接收ByteArrayOutputStream bos = (ByteArrayOutputStream) selectionKey.attachment();ByteBuffer buffer = ByteBuffer.allocate(10240);// 10kb缓存int actual = 0;while ((actual = client.read(buffer)) > 0) {buffer.flip();int limit = buffer.limit();byte b[] = new byte[limit];buffer.get(b);bos.write(b);buffer.clear();// 清空}if (actual < 0) {// 出现异常selectionKey.cancel();client.socket().close();client.close();throw new EOFException("Read EOF");}bos.flush();byte[] data = bos.toByteArray();bos.reset();return data;}return null;}public final boolean writeBuf(byte[] data) throws Exception {if (client.isConnected()) {ByteBuffer buffer = ByteBuffer.wrap(data);int size = buffer.remaining();// 此处需加中途断开逻辑,下次再继续发送数据包int actually = client.write(buffer);if (actually == size)return true;}return false;}/** * 唤起连接线程重新连接 */protected synchronized void reconnect() {notify();}private synchronized void connect() {try {selector = Selector.open();InetSocketAddress isa = new InetSocketAddress(ip, port);client = SocketChannel.open();// 设置连超时client.socket().connect(isa, CONNECT_TIMEOUT);// 设置读超时client.socket().setSoTimeout(READ_TIMEOUT);client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ,new ByteArrayOutputStream());if (client.isConnected()) {// 连接成功开始监听服务端消息// 发送一个验证数据包到服务器进行验证STATE = RUNNING;if (connectListener != null)connectListener.connect(ENUM_CONNECT.STATUS_OK);MLog.makeText("连接成功");} else {// 关闭通道过60S重新开始连接if (connectListener != null)connectListener.connect(ENUM_CONNECT.STATUS_FAIL);StringBuffer buffer = new StringBuffer("服务器连接失败");buffer.append(RECONNECT_TIME_SECOND);buffer.append("秒后再尝试连接");MLog.makeText(buffer);close();// 关闭通道Wait(RECONNECT_TIME);}} catch (Exception e) {// TODO Auto-generated catch block// 有异常关闭通道过60S重新开始连接e.printStackTrace();StringBuffer buffer = new StringBuffer("连接出错啦!");buffer.append(RECONNECT_TIME_SECOND);buffer.append("秒后再尝试连接");MLog.makeText(buffer);close();// 关闭通道Wait(RECONNECT_TIME);}}public void close() {STATE = CONNECT;try {if (client != null) {client.socket().close();client.close();client = null;}if (selector != null) {selector.close();selector = null;}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private void closeKey(SelectionKey key) {if (key != null) {key.cancel();try {key.channel().close();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();StringBuffer buffer = new StringBuffer("连接断开啦!");buffer.append(RECONNECT_TIME_SECOND);buffer.append("秒后再尝试连接");MLog.makeText(buffer);Wait(RECONNECT_TIME);}}close();}private void Wait(long millis) {try {wait(millis);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public ConnectListener getConnectListener() {return connectListener;}public void setConnectListener(ConnectListener connectListener) {this.connectListener = connectListener;}public interface ConnectListener {public void connect(ENUM_CONNECT STATUS);}}

IT十万为什么 » Android使用NIO开发客户端

更多相关文章

  1. android的Http请求组件
  2. Android(安卓)系统监听,监听USB的插拔
  3. android > android 客户端 ,PHP 服务器端 HttpGet类和HttpPost类
  4. Android(安卓)Ble
  5. adb connect 失败时(unable to connect to)解决办法
  6. 编译V8静态库 for Android
  7. Android(安卓)轮询实现的三种方式
  8. android HttpURLConnection 连接网络 读取返回数据
  9. Android通过http协议POST传输方式

随机推荐

  1. Android(安卓)app version code and name
  2. android:inputType 参数详解
  3. android:inputType参数类型说明
  4. android系统自带的主题与样式(theme and
  5. android:inputType参数类型说明
  6. android:inputType参数类型说明
  7. Android(安卓)控件和其基本属性1
  8. Android附带Theme总结
  9. Android系统自带样式(@android:style/)
  10. android按钮旋转简单实现