NioSocket相關知識

一、Nio簡介

nio 是non-blocking的簡稱,在jdk1.4 裏提供的新api 。Sun 官方標榜的特性如下: 爲所有的原始類型提供(Buffer)緩存支持。字符集編碼解碼解決方案。 Channel :一個新的原始I/O 抽象。 支持鎖和內存映射文件的文件訪問接口。 提供多路(non-bloking) 非阻塞式的高伸縮性網絡I/O 。

java.nio包是Java在1.4之後增加的,用來提高I/O操作的效率。在nio包中主要包括以下幾個類或接口:

* Buffer:緩衝區,用來臨時存放輸入或輸出數據。
* Charset:用來把Unicode字符編碼和其它字符編碼互轉。
* Channel:數據傳輸通道,用來把Buffer中的數據寫入到數據源,或者把數據源中的數據讀入到Buffer。
* Selector:用來支持異步I/O操作,也叫非阻塞I/O操作。

nio包中主要通過下面兩個方面來提高I/O操作效率:

* 通過Buffer和Channel來提高I/O操作的速度。
* 通過Selector來支持非阻塞I/O操作。

傳送門:NIO與IO的區別

二、NioSocket

NIO爲socket提供了新的連接方式。使用NioSocket的流程如下:

Created with Raphaël 2.1.0開始建立ServerSocketChannel設置相應的參數。創建Selector並註冊到ServerSocketChannel上。調用Selector的select方法等待請求,可以制定超時時間。Selector接收到請求後使用selectedKeys返回SelectionKey集合。使用SelectionKey獲取到Channel、Selector和操作類型並進行具體的操作。結束

三、服務器示例代碼

package com.frank.java.util;

/**
 * Created by Administrator on 2016/6/24.
 */
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.nio.charset.Charset;
import java.util.Iterator;

public class NIOServer {
    public static void main(String[] args) throws Exception{
        //創建ServerSocketChannel,監聽8080端口
        ServerSocketChannel ssc=ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress(8081));
        //設置爲非阻塞模式
        ssc.configureBlocking(false);
        //爲ssc註冊選擇器
        Selector selector=Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        //創建處理器
        Handler handler = new Handler(1024);
        while(true){
            // 等待請求,每次等待阻塞3s,超過3s後線程繼續向下運行,如果傳入0或者不傳參數將一直阻塞
            if(selector.select(3000)==0){
                System.out.println("等待請求超時。。。");
                continue;
            }
            System.out.println("處理請求。。。");
            // 獲取待處理的SelectionKey
            Iterator<SelectionKey> keyIter=selector.selectedKeys().iterator();

            while(keyIter.hasNext()){
                SelectionKey key=keyIter.next();
                try{
                    // 接收到連接請求時
                    if(key.isAcceptable()){
                        handler.handleAccept(key);
                    }
                    // 讀數據
                    if(key.isReadable()){
                        handler.handleRead(key);
                    }
                } catch(IOException ex) {
                    keyIter.remove();
                    continue;
                }
                // 處理完後,從待處理的SelectionKey迭代器中移除當前所使用的key
                keyIter.remove();
            }
        }
    }

    private static class Handler {
        private int bufferSize = 1024;
        private String  localCharset = "UTF-8";

        public Handler(){}
        public Handler(int bufferSize){
            this(bufferSize, null);
        }
        public Handler(String  LocalCharset){
            this(-1, LocalCharset);
        }
        public Handler(int bufferSize, String  localCharset){
            if(bufferSize>0)
                this.bufferSize=bufferSize;
            if(localCharset!=null)
                this.localCharset=localCharset;
        }

        public void handleAccept(SelectionKey key) throws IOException {
            SocketChannel sc=((ServerSocketChannel)key.channel()).accept();
            sc.configureBlocking(false);
            sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        }

        public void handleRead(SelectionKey key) throws IOException {
            // 獲取channel
            SocketChannel sc=(SocketChannel)key.channel();
            // 獲取buffer並重置
            ByteBuffer buffer=(ByteBuffer)key.attachment();
            buffer.clear();
            // 沒有讀到內容則關閉
            if(sc.read(buffer)==-1){
                sc.close();
            } else {
                // 將buffer轉換爲讀狀態
                buffer.flip();
                // 將buffer中接收到的值按localCharset格式編碼後保存到receivedString
                String receivedString =                Charset.forName(localCharset).newDecoder().decode(buffer).toString();
                System.out.println("received from client: " + receivedString);

                // 返回數據給客戶端
                String sendString = "received data: " + receivedString;
                buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
                sc.write(buffer);
                // 關閉Socket
                sc.close();
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章