1. 程式人生 > >Java NIO Buffer Channel Selector

Java NIO Buffer Channel Selector

1、緩衝區型別:

ByteBuffer
CharBuffer
ShortBufer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer,並沒有 BooleanBuffer

2、ByteBuffer 基本操作

import java.nio.ByteBuffer;

public class MainNioTest {

	public static void main(String[] args) {
		//初始化
		ByteBuffer buffer = ByteBuffer.allocate(10);
		//儲存
		buffer.put("1234567".getBytes());
		//反轉(讀寫轉換)
		buffer.flip();
		//讀取
		while (buffer.hasRemaining()) {
			System.out.print((char)buffer.get());
		}
	}
}

3、ByteBuffer 繼承類

HeapByteBuffer 分配在jvm堆記憶體
DirectByteBuffer 直接分配在記憶體
DirectByteBufferR 返回只一個只讀物件,無法寫操作
MappedByteBuffer 大檔案操作

4、Channel通道型別

FileChannel:從檔案中讀寫資料
DatagramChannel:能通過UDP讀寫網路中的資料。
SocketChannel:能通過TCP讀寫網路中的資料。
ServerSocketChannel:可以監聽新進來的TCP連線,像Web伺服器那樣。對每一個新進來的連線都會建立一個SocketChannel

5、Buffer和Channel

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class MainNIoChannel {

	public static void main(String[] args) throws Exception {
		String path = "D:"+File.separator+"data.txt";

        RandomAccessFile aFile = new RandomAccessFile(path,"rw");
        FileChannel channel = aFile.getChannel();//得到管道
        //藉助一個Buffer來與Channel進行互動
        ByteBuffer buffer = ByteBuffer.allocate(1025);
        int readByteLen;
        while((readByteLen = channel.read(buffer)) != -1){
            System.out.println("讀取到buffer中的資料長度為:"+readByteLen);
            System.out.println("內容如下:");
            //將Buffer從寫模式切換到讀模式
            buffer.flip();
            while(buffer.hasRemaining()){
                System.out.print((char)buffer.get());
            }
            buffer.clear();

            System.out.println();//換行
        }
        aFile.close();
	}
}

6、Selector

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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class MainSelectorServer {

	public static void main(String[] args) throws Exception {
		MainSelectorServer server = new MainSelectorServer();
        server.init(9999);
        server.listen();
	}

	// 通道選擇器
	private Selector selector;

	public MainSelectorServer(){
        try {
            selector = Selector.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

	/*
	 * 函式功能:伺服器端開始監聽,看是否有客戶端連線進來
	 */
	private void listen() throws Exception {
		System.out.println("server running....");
		while (true) {
			// 當註冊事件到達時,方法返回,否則該方法會一直阻塞
			selector.select();
			// 獲得selector中選中的相的迭代器,選中的相為註冊的事件
			Set<SelectionKey> set = selector.selectedKeys();
			Iterator<SelectionKey> ite = set.iterator();
			while (ite.hasNext()) {
				SelectionKey selectionKey = (SelectionKey) ite.next();
				// 刪除已選的key 以防重負處理
				ite.remove();
				if (selectionKey.isAcceptable()) {// 如果有客戶端連線進來
					// 先拿到這個SelectionKey裡面的ServerSocketChannel。
					ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
					SocketChannel socketChannel = serverSocketChannel.accept();
					System.out.println("有客戶端連線到伺服器!!!");
					socketChannel.configureBlocking(false);// 將此通道設定為非阻塞
					Thread.sleep(2000);
					socketChannel.write(ByteBuffer.wrap(new String("hello client!").getBytes()));
					socketChannel.register(selector, SelectionKey.OP_READ);
				} else if (selectionKey.isReadable()) {// 客戶端傳送資料過來了
					// 先拿到這個SelectionKey裡面的SocketChannel。
					SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
					// 接收來自於客戶端傳送過來的資料
					ByteBuffer buf = ByteBuffer.allocate(13);
					while (socketChannel.read(buf) != -1) {
						byte[] receData = buf.array();
						String msg = new String(receData).trim();
						Thread.sleep(2000);
						System.out.println("接收來自客戶端的資料為:" + msg);
						buf.clear();
					}
				}
			}
		}
	}

	/*
	 * 函式功能:初始化serverSocketChannel來監聽指定的埠是否有新的TCP連線,
	 * 並將serverSocketChannel註冊到selector中
	 */
	private void init(int port) {
		try {
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
			// serverSocketChannel監聽指定埠
			serverSocketChannel.socket().bind(new InetSocketAddress(port));
			serverSocketChannel.configureBlocking(false);// 設定為非阻塞模式
			// 將serverSocketChannel註冊到selector中,併為該通道註冊selectionKey.OP_ACCEPT事件
			// 註冊該事件後,當事件到達的時候,selector.select()會返回, 如果事件沒有到達selector.select()會一直阻塞
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
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;

public class MainSelectorClient {

	public static void main(String[] args) throws Exception {
		MainSelectorClient client = new MainSelectorClient();
		client.init("localhost", 9999);
		client.connect();
	}

	private Selector selector;

	public MainSelectorClient() throws IOException {
		this.selector = Selector.open();
	}

	private void init(String address, int port) throws IOException {
		// 客戶端,首先有一個SocketChannel
		SocketChannel socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);// 將此通道設定為非阻塞模式
		socketChannel.connect(new InetSocketAddress(address, port));
		// 將SocketChannel註冊到selector中,併為該通道註冊SelectionKey.OP_CONNECT
		socketChannel.register(selector, SelectionKey.OP_CONNECT);
	}

	private void connect() throws Exception {
		while (true) {
			selector.select();
			Set<SelectionKey> set = selector.selectedKeys();
			Iterator<SelectionKey> ite = set.iterator();
			while (ite.hasNext()) {
				SelectionKey selectionKey = (SelectionKey) ite.next();
				ite.remove(); // 刪除已選的key,以防重複處理
				if (selectionKey.isConnectable()) {// 看是否有連線發生
					SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
					// 如果正在連線,則完成連線
					if (socketChannel.isConnectionPending()) {
						socketChannel.finishConnect();
					}
					socketChannel.configureBlocking(false);// 設定為非阻塞模式
					// 給伺服器端傳送資料
					System.out.println("客戶端連線上了伺服器端。。。。");
					Thread.sleep(2000);
					socketChannel.write(ByteBuffer.wrap(new String("hello server!").getBytes()));
					// 為了接收來自伺服器端的資料,將此通道註冊到選擇器中
					socketChannel.register(selector, SelectionKey.OP_READ);
				} else if (selectionKey.isReadable()) {
					SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
					// 接收來自於伺服器端傳送過來的資料
					ByteBuffer buf = ByteBuffer.allocate(13);
					while (socketChannel.read(buf) != -1) {
						byte[] receData = buf.array();
						String msg = new String(receData).trim();
						Thread.sleep(2000);
						System.out.println("接收來自伺服器端的資料為:" + msg);
						buf.clear();
					}
				}
			}
		}
	}
}