Netty之BIO(同步阻塞IO)、PIO(伪异步阻塞IO)、NIO(异步非阻塞IO)、AIO(异步非阻塞IO)

来源:互联网 发布:python 数组去除重复 编辑:程序博客网 时间:2024/05/21 21:21

学习书籍:Netty权威指南

多种IO方式的比较:

1、BIO(同步阻塞IO)

使用ServerSocket绑定IP地址和监听端口,客户端发起连接,通过三次握手建立连接,用socket来进行通信,通过输入输出流的方式来进行同步阻塞的通信

每次客户端发起连接请求,都会启动一个线程

线程数量:客户端并发访问数为1:1,由于线程是Java虚拟机中非常宝贵的资源,一旦线程数急剧增加,系统性能会急剧下降,导致线程栈溢出,创建新的线程失败,并最终导致宕机

所以在JDK1.4之前,人们想到了一种方法,即PIO方式

2、PIO(伪异步阻塞IO)

使用线程池来处理客户端的请求

客户端个数:线程池最大线程数=M:N,其中M远大于N

在read和write的时候,还是IO阻塞的,只是把每个线程交由线程池来控制管理

3、NIO(异步阻塞IO)

用NIO方式处理IO

使用多路复用器Selector来轮询每个通道Channel,当通道中有事件时就通知处理,不会阻塞

使用相当复杂


服务器实现模式为一个请求一个线程,客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

4、AIO(真正的异步非阻塞IO)

NIO2.0引入了新的异步通道的概念,不需要使用多路复用器(Selector)对注册通道进行轮询即可实现异步读写,从而简化了NIO编程模型


使用Netty框架进行编程步骤

1、构建事件处理池

2、使用引导程序关联事件处理池、通道、事件处理器

3、绑定端口服务

4、等待操作完成

5、关闭事件处理池


几种IO的功能和特性对比



按照书上的例子码了一遍:

服务端:

[java] view plain copy
 print?
  1. import io.netty.bootstrap.ServerBootstrap;  
  2. import io.netty.channel.ChannelFuture;  
  3. import io.netty.channel.ChannelInitializer;  
  4. import io.netty.channel.ChannelOption;  
  5. import io.netty.channel.EventLoopGroup;  
  6. import io.netty.channel.nio.NioEventLoopGroup;  
  7. import io.netty.channel.socket.SocketChannel;  
  8. import io.netty.channel.socket.nio.NioServerSocketChannel;  
  9.   
  10. public class NettyServer {  
  11.     public void bind(int port) throws Exception {  
  12.         EventLoopGroup bossGroup = new NioEventLoopGroup();  
  13.         EventLoopGroup workGroup = new NioEventLoopGroup();  
  14.         try {  
  15.             ServerBootstrap b = new ServerBootstrap();  
  16.             b.group(bossGroup, workGroup).channel(NioServerSocketChannel.class)  
  17.                     .option(ChannelOption.SO_BACKLOG, 1024)  
  18.                     .childHandler(new ChildChannelHandler());  
  19.             // 绑定端口,同步等待成功  
  20.             ChannelFuture f = b.bind(port).sync();  
  21.             // 等待服务端监听端口关闭  
  22.             f.channel().closeFuture().sync();  
  23.         } catch (Exception e) {  
  24.             // TODO: handle exception  
  25.         } finally {  
  26.             // 优雅退出,释放线程池资源  
  27.             bossGroup.shutdownGracefully();  
  28.             workGroup.shutdownGracefully();  
  29.         }  
  30.     }  
  31.   
  32.     private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {  
  33.         @Override  
  34.         protected void initChannel(SocketChannel ch) throws Exception {  
  35.             ch.pipeline().addLast(new NettyServerHandle());  
  36.         }  
  37.     }  
  38.   
  39.     public static void main(String[] args) throws Exception {  
  40.         int port = 8080;  
  41.         if (args != null && args.length > 0) {  
  42.             try {  
  43.                 port = Integer.valueOf(args[0]);  
  44.             } catch (Exception e) {  
  45.                 e.printStackTrace();  
  46.             }  
  47.         }  
  48.         new NettyServer().bind(port);  
  49.     }  
  50. }  


服务端处理器:

[java] view plain copy
 print?
  1. import io.netty.buffer.ByteBuf;  
  2. import io.netty.buffer.Unpooled;  
  3. import io.netty.channel.ChannelHandlerAdapter;  
  4. import io.netty.channel.ChannelHandlerContext;  
  5.   
  6. public class NettyServerHandle extends ChannelHandlerAdapter {  
  7.     public void channelRead(ChannelHandlerContext ctx, Object msg)  
  8.             throws Exception {  
  9.         ByteBuf buf = (ByteBuf) msg;  
  10.         byte[] req = new byte[buf.readableBytes()];  
  11.         buf.readBytes(req);  
  12.         String body = new String(req, "UTF-8");  
  13.         System.out.println("The time server receive order:" + body);  
  14.         String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(  
  15.                 System.currentTimeMillis()).toString() : "BAD ORDER";  
  16.         ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());  
  17.         ctx.write(resp);  
  18.     }  
  19.   
  20.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
  21.         ctx.flush();  
  22.     }  
  23.   
  24.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
  25.         ctx.close();  
  26.     }  
  27. }  

客户端:

[java] view plain copy
 print?
  1. import io.netty.bootstrap.Bootstrap;  
  2. import io.netty.channel.ChannelFuture;  
  3. import io.netty.channel.ChannelInitializer;  
  4. import io.netty.channel.ChannelOption;  
  5. import io.netty.channel.EventLoopGroup;  
  6. import io.netty.channel.nio.NioEventLoopGroup;  
  7. import io.netty.channel.socket.SocketChannel;  
  8. import io.netty.channel.socket.nio.NioSocketChannel;  
  9.   
  10. public class NettyClient {  
  11.     public void connect(int port, String host) throws Exception {  
  12.         // 1、创建线程池  
  13.         EventLoopGroup group = new NioEventLoopGroup();  
  14.         try {  
  15.             // 2、使用引导器关联线程池、通道、通达处理器、设置执行参数  
  16.             Bootstrap b = new Bootstrap();  
  17.             b.group(group).channel(NioSocketChannel.class)  
  18.                     .option(ChannelOption.TCP_NODELAY, true)  
  19.                     .handler(new ChannelInitializer<SocketChannel>() {  
  20.                         @Override  
  21.                         protected void initChannel(SocketChannel ch)  
  22.                                 throws Exception {  
  23.                             ch.pipeline().addLast(new NettyClientHandle());  
  24.                         }  
  25.                     });  
  26.             // 发起异步连接操作 3、绑定端口同步操作  
  27.             ChannelFuture f = b.connect(host, port).sync();  
  28.             // 4、监听端口关闭  
  29.             f.channel().closeFuture().sync();  
  30.         } catch (Exception e) {  
  31.             // TODO: handle exception  
  32.         } finally {  
  33.             // 优雅退出,释放NIO线程组 5、释放资源  
  34.             group.shutdownGracefully();  
  35.         }  
  36.     }  
  37.   
  38.     public static void main(String[] args) throws Exception {  
  39.         int port = 8080;  
  40.         if (args != null && args.length > 0) {  
  41.             try {  
  42.                 port = Integer.valueOf(args[0]);  
  43.             } catch (Exception e) {  
  44.                 e.printStackTrace();  
  45.             }  
  46.         }  
  47.         new NettyClient().connect(port, "127.0.0.1");  
  48.     }  
  49. }  

客户端处理器:

[java] view plain copy
 print?
  1. import io.netty.buffer.ByteBuf;  
  2. import io.netty.buffer.Unpooled;  
  3. import io.netty.channel.ChannelHandlerAdapter;  
  4. import io.netty.channel.ChannelHandlerContext;  
  5.   
  6. import java.util.logging.Logger;  
  7.   
  8. public class NettyClientHandle extends ChannelHandlerAdapter {  
  9.     private static final Logger logger = Logger  
  10.             .getLogger(NettyClientHandle.class.getName());  
  11.     private final ByteBuf firstMessage;  
  12.   
  13.     public NettyClientHandle() {  
  14.         byte[] req = "QUERY TIME ORDER".getBytes();  
  15.         firstMessage = Unpooled.buffer(req.length);  
  16.         firstMessage.writeBytes(req);  
  17.     }  
  18.   
  19.     public void channelActive(ChannelHandlerContext ctx) {  
  20.         ctx.writeAndFlush(firstMessage);  
  21.     }  
  22.   
  23.     public void channelRead(ChannelHandlerContext ctx, Object msg)  
  24.             throws Exception {  
  25.         ByteBuf buf = (ByteBuf) msg;  
  26.         byte[] req = new byte[buf.readableBytes()];  
  27.         buf.readBytes(req);  
  28.         String body = new String(req, "UTF-8");  
  29.         System.out.println("Now is:" + body);  
  30.     }  
  31.   
  32.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
  33.         // 释放资源  
  34.         logger.warning("Unexpected exception from downstream:"  
  35.                 + cause.getMessage());  
  36.         ctx.close();  
  37.     }  
  38. }  
1 0