028-86261949

当前位置:首页 > 技术交流 > 利用NIO模拟实现Tomcat容器

利用NIO模拟实现Tomcat容器

2019/08/15 17:06 分类: 技术交流 浏览:0

 

NIO是什么

  1. New IO,始于Java1.4,提供新的非阻塞 JavaIO 操作API.
  2. 又称Non-Blocking IO 非阻塞IO
  3. 替代旧版本的Blocking IO, 多用于网络相关的API.

 

为什么要使用NIO

使用NIO后,WEB网络程序性能可以进一步提高

 

模拟Tomcat7, 阻塞IO处理Http请求:

public class BIOHttpServer {

    public static void main(String[] args) throws IOException {

        ServerSocket socket = new ServerSocket(8080);

        System.out.println(Thread.currentThread().getName()+"启动:"+8080);

        while(true){

            Socket accept = socket.accept();

                InputStream inputStream = accept.getInputStream();

                byte[] b = new byte[1024];

                inputStream.read(b);

                System.out.println(new String(b));

               

                // http响应头 必须这样写:

                String response = "HTTP/1.1 200 ok\r\nContent-Length: 11\r\n\r\nHello World\r\n";

                accept.getOutputStream().write(response.getBytes());

                accept.getOutputStream().flush();

                accept.close();         

        }

    }

}

 

 

NIO高性能的核心原理:

  1. 发起连接
  2. 操作系统接收连接
  3. TCP模块 + 多路复用机制
  4. 一个Java线程通过Selector工具选择性处理
  5. 有数据传输的交给线程池
  6. 最终达到,线程最大程度利用

 

 

使用NIO:

 

模拟Tomcat8.5, NIO处理Http请求:

public class NIOHttpServer {

    public static void main(String[] args) throws IOException {

 

        // 1.ServerSocketChannel 绑定端口

        ServerSocketChannel socket = ServerSocketChannel.open();

        socket.configureBlocking(false); // no-Blocking

        socket.bind(new InetSocketAddress(8080));

 

        System.out.println("NIO服务器启动,端口:"+8080);

 

        // 2.获取新连接

        // selector 获取不同操作系统下不同的tcp连接动态

        Selector selector = Selector.open();

       

        // 选择器,根据条件查询符合情况地TCP连接

        socket.register(selector, SelectionKey.OP_ACCEPT);

       

        while(true){

            selector.select(1000); //如果没有新连接,就等待

           

            // 3. 处理查询结果

            Set<SelectionKey> keys = selector.selectedKeys();

            Iterator<SelectionKey> iterator = keys.iterator();

   

            while(iterator.hasNext()){

                SelectionKey result = iterator.next();

               

                //根据不同的类型,分别进行处理

                if(result.isAcceptable()){ //3.1 拿到新连接对象

                    // nio体现,accept 不阻塞,没有连接则返回null

                    SocketChannel accept = socket.accept();

                    if(accept!=null){

                        // 注册连接对象,进行关注

                        accept.configureBlocking(false);// no-Blocking

                        accept.register(selector, SelectionKey.OP_READ);

                    }

                }

                if(result.isReadable()){ //3.2 有数据请求的连接

                    SocketChannel channel = (SocketChannel) result.channel();

                    // 处理过程中,先取消selector对应连接的注册,避免重复

                    result.cancel();

                   

                    // NIO的读写方式: 字节缓冲区

                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                    channel.read(byteBuffer);

                    byteBuffer.flip(); //模式转换

                    byte[] b = byteBuffer.array();

                    String request = new String(b);

                   

                    //处理请求...

                    System.out.println(request);

 

                    //数据响应:NIO的写数据

                    String response = "HTTP/1.1 200 ok\r\nContent-Length: 11\r\n\r\nHello World\r\n";

                    channel.write(ByteBuffer.wrap(response.getBytes()));

                   

                    // 处理完成,重新注册,继续接收处理新的连接

                    // channel.register(selector, SelectionKey.OP_READ);

                }

                // 删除处理过的结果(事件)

                iterator.remove();

            }  

           

            // 检查过程就绪,清除之前的调用效果

            selector.selectNow();

        }

    }

}

 

#标签:NIO模拟,Tomcat容器