手寫tomcat系列之NIO

原文鏈接:https://www.cnblogs.com/barrywxx/p/8430790.html

目標

1.理解什麼是NIO,優劣情況等...

2.其實想補充一點自己的理解,但是怕寫出來誤導人,這裏就暫時不'扯'了...

 

參考博文

1.https://www.cnblogs.com/barrywxx/p/8430790.html

2.https://blog.csdn.net/knight_black_bob/article/details/88223838

 

核心代碼

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 tomcat.base.TomcatModule;

public class NIOModule implements TomcatModule,Runnable{

	// 多路複選器
	private Selector selector;
	// 緩衝區
	private ByteBuffer writeBuf = ByteBuffer.allocate(1024);
	private ByteBuffer readBuf = ByteBuffer.allocate(1024);
	
	@Override
	public void createLink() {
		new Thread(this).start();
	}
	
	@Override
	public void run() {
		try {
			this.initSelector();
			this.doSomething();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 1 打開多路複用器
	 * 2 打開服務器通道
	 * 3 設置服務器通道爲非阻塞模式
	 * 4 綁定地址
	 * 5 把服務器通道註冊到多路複用器上,並且監聽阻塞事件
	 * @param     參數
	 * @date 2019年8月19日 下午3:54:52
	 * @return void    
	 * @throws
	 */
	private void initSelector() {
		try {
			this.selector = Selector.open();
	        ServerSocketChannel ssc = ServerSocketChannel.open();
	        ssc.configureBlocking(false);
	        ssc.bind(new InetSocketAddress(8888));
	        ssc.register(this.selector, SelectionKey.OP_ACCEPT);
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	private void doSomething() {
		try {
			while(true) {
				this.selector.select();
				Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator();
				while(keys.hasNext()) {
					SelectionKey key = keys.next();
					keys.remove();
					if(key.isValid()) {
						if(key.isAcceptable()) {	// 判斷爲阻塞狀態
							this.accept(key);
						} else if(key.isReadable()) {	// 判斷爲讀取狀態
							this.read(key);
							this.write(key);
						} 
					}
				}
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	private void write(SelectionKey key){
        try {
        	SocketChannel sc =  (SocketChannel) key.channel();
			sc.register(this.selector, SelectionKey.OP_WRITE);
			this.writeBuf.clear();
			this.writeBuf.put("sixogd".getBytes("UTF-8"));
			this.writeBuf.flip();
			sc.write(this.writeBuf);
			this.writeBuf.clear();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
            if(null!=key)key.cancel();
		}
    }

    private void read(SelectionKey key) {
        try {
            //1 清空緩衝區舊的數據
            this.readBuf.clear();
            //2 獲取之前註冊的socket通道對象
            SocketChannel sc = (SocketChannel) key.channel();
            //3 讀取數據
            int count = sc.read(this.readBuf);
            //4 如果沒有數據
            if(count != -1){
                //5 有數據則進行讀取 讀取之前需要進行復位方法(把position 和limit進行復位)
                this.readBuf.flip();
                //6 根據緩衝區的數據長度創建相應大小的byte數組,接收緩衝區的數據
                byte[] bytes = new byte[this.readBuf.remaining()];
                //7 接收緩衝區數據
                this.readBuf.get(bytes);
                //8 打印結果
                String body = new String(bytes).trim();
                System.out.println("Server : " + body);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 1 獲取服務通道
     * 2 執行阻塞方法
     * 3 設置阻塞模式
     * 4 註冊到多路複用器上,並設置讀取標識
     * @param @param key    參數
     * @date 2019年8月19日 下午4:03:10
     * @return void    
     * @throws
     */
    private void accept(SelectionKey key) {
        try {
            ServerSocketChannel ssc =  (ServerSocketChannel) key.channel();
            SocketChannel sc = ssc.accept();
            sc.configureBlocking(false);
            sc.register(this.selector, SelectionKey.OP_READ);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章