手写tomcat系列之NIO

目标

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 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();
        }
    }

}

 

 

你可能感兴趣的:(socket)