Java NIO (一)

  具備非阻塞、信道複用等特性的JAVA NIO極大地提高了TCP通信的效率,由於JAVA NIO具有非阻塞的特性,所以基於這一特性可以使用一個線管理多個鏈接。下面的程序演示了在不使用Selector的情況下簡單模擬了一個TCP服務器的搭建和客戶端的訪問:

1,服務器類Server.java

package com.zws.nio.nosel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

import com.zws.nio.util.NIOHelper;

public class Server extends Thread{
	
	private ServerSocketChannel sevChn = null;
	private SocketChannel chn = null;
	private boolean block = false;
	private int port;
	
	public Server(int port) {
		this.port = port;
		init();
	}

	@Override
	public void run() {
		while (!isInterrupted()) {
			try {
				//此處的accept方法是一個非阻塞的方法,即不管有沒有客戶端鏈接都會返回,在沒有客戶端鏈接的情況下返回null。
				if ((chn = sevChn.accept()) != null) {
					String msg = NIOHelper.read(chn);
					System.out.println("Server gets msg:" + msg);
					
					msg = "Hello Client...";
					NIOHelper.write(chn, msg);
					chn.close();
				} else {
					//do something else
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/*
	 * 初始化ServerSocketChannel、SocketChannel
	 */
	private void init() {
		try {
			sevChn = ServerSocketChannel.open();
			sevChn.configureBlocking(block);//配置阻塞,false:非阻塞,true:阻塞
			sevChn.socket().bind(new InetSocketAddress(port));
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	/**
	 * 關閉服務器
	 */
	public void close() {
		this.interrupt();
		if (sevChn != null)
			try {
				sevChn.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	}

	public static void main(String[] args) {
		Server server = new Server(9003);
		server.start();
		//server.close();
	}
}

2,客戶端類:Client.java

package com.zws.nio.nosel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;

import com.zws.nio.util.NIOHelper;

public class Client {

	public static void main(String[] args) {
		boolean block = false;
		SocketChannel chn = null;
		try {
			chn = SocketChannel.open();
			chn.connect(new InetSocketAddress("localhost", 9003));
			chn.configureBlocking(block);
			while (true) {
				//是否完成鏈接,非阻塞方法。
				if (chn.finishConnect()) {
					String msg = "Hello Server...";
					NIOHelper.write(chn, msg);
					
					msg = NIOHelper.read(chn);
					System.out.println("Client gets msg:" + msg);
					break;
				} else {
					//do something else
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (chn != null)
				try {
					chn.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

3,輔助類:NIOHelper.java

package com.zws.nio.util;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOHelper {
	public static final String CHARSET_UTF8 = "UTF-8";

	public static void write(SocketChannel chn, String msg) throws IOException {
		
		byte[] bts = msg.getBytes(CHARSET_UTF8);
		int len = bts.length;
		ByteBuffer buffer = ByteBuffer.allocate(len + 4);
		buffer.put(IntegerUtil.toBytes(len));//前4個字節爲報文長度
		buffer.put(bts);
		buffer.flip();
		while (buffer.hasRemaining())
			chn.write(buffer);
	}
	
	public static String read(SocketChannel chn) throws IOException {
		String msg = null;
		byte[] bts = new byte[4];
		ByteBuffer buffer = ByteBuffer.allocate(4);
		while (chn.read(buffer) == 0) {}
		buffer.flip();
		buffer.get(bts, 0, buffer.remaining());
		
		int size = IntegerUtil.toInt(bts);
		buffer = ByteBuffer.allocate(size);
		while (chn.read(buffer) == 0) {}
		buffer.flip();
		bts = new byte[size];
		buffer.get(bts, 0, buffer.remaining());
		msg = new String(bts,CHARSET_UTF8);
		return msg;
	}
}

4,輔助類:IntegerUtil.java

package com.zws.nio.util;

public class IntegerUtil {

	/**
	 * 將int轉化成4字節數組
	 * @param value
	 * @return
	 */
	public static byte[] toBytes(int value) {
	    byte[] bytes = new byte[4];
	    for (int i = 0; i < 4; i++) {
	        bytes[i] = (byte) (value >> 8 * i & 0xFF);
	    }
	    return bytes;
	}
	/**
	 * 字節數組轉化int
	 * @param bytes
	 * @return
	 */
	public static int toInt(byte[] bytes) {
	    int value = 0;

	    for (int i = 0; i < bytes.length; i++) {
	        byte item = bytes[i];
	        value += (item & 0xFF) << (8 * i);
	    }
	    return value;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章