1.- Netty设计理念-异步和事件驱动

0. 关键点

a). 非阻塞网络调用,异步方法立即返回
b). 选择器(Selector)使得单一线程就可监控很多连接上的事件。

	<dependency>
		<groupId>io.netty</groupId>
		<artifactId>netty-all</artifactId> <!-- Use 'netty-all' for 4.0 or above -->
		<version>4.1.13</version>
		<scope>compile</scope>
	</dependency>

1.1 Channel-类似socket,管道

1.2 回调-操作完成时调用

1.3 Future-异步通知--更精确的异步

类似更精确的异步。
JDK预置concurrent.Future需要手动检查对应的操作是否已完成,非常繁琐。
Netty封装成ChannelFuture消除手动检查,可注册一或多个ChannelFutureListner,回调方法operationComplete()操作完成时调用,可检查是成功还是失败了。

Channel channel = null;
ChannelFuture future = channel.connect(new InetSocketAddress("127.0.0.1", 8888));
//注册监测异步事件调用完成
future.addListener(new ChannelFutureListener() {
	@Override
	public void operationComplete(ChannelFuture future) throws Exception {
		if( future.isSuccess()){
			//异步调用成功
			ByteBuf buffer = Unpooled.copiedBuffer("Hello", CharsetUtil.UTF_8);
			future.channel().write(buffer);
		} else {
			//异步调用失败
			Throwable cause = future.cause();
			cause.printStackTrace();
		}
	}
});

1.4 事件和ChannelHandler-链

1.5 EventLoop-处理所有IO事件-多线程处理

为每一个channel分配一个EventLoop,处理所有的事件,包括:注册感兴趣的事件、将事件派发给ChannelHandler,安排进一步的动作。
EventLoop本身只由一个线程驱动,处理一个Channel的所有IO事件,并且在整个生命周期不变(不需考虑同步问题)。

1.8 实例代码

1.8.1 server代码

//测试结果
Received Connect, remote IP:/127.0.0.1:56015	//c连接上时打印
channelRead Invoked!!
Server Received:1111111111111111111111111
channelReadComplete Invoked!!!
Received Connect, remote IP:/127.0.0.1:56018
public class EchoServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();  //引导类,BS端不同
            b.group(bossGroup, workerGroup)     //master主线程,slaves处理handler的线程池
                    .channel(NioServerSocketChannel.class)  //何种channel(socket),BS端不同
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //当一个新连接被接受时,一个新的子channel被创建,将处理类实例添加到ChannelPipeLine(链)中
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });

            //绑定端口,sync()阻塞到调用完成
            ChannelFuture f = b.bind(8888).sync();
            //阻塞到关闭完成
            f.channel().closeFuture().sync();
        } finally {
            //关闭EventLoopGroup直到完成
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }
}
public class EchoServerHandler  extends ChannelInboundHandlerAdapter{
    @Override
    public void channelActive(ChannelHandlerContext ctx){
        System.out.println("Received Connect, remote IP:"+ctx.channel().remoteAddress());
    }

    @Override
    //对每个传入的消息都要调用,存在TCP粘连的问题
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("channelRead Invoked!!");
        ByteBuf in = (ByteBuf) msg;
        System.out.println("Server Received:" + in.toString(CharsetUtil.UTF_8));
        ctx.write(in);
    }

    @Override
    //读取完当前批次消息时调用
    public void channelReadComplete(ChannelHandlerContext ctx){
        System.out.println("channelReadComplete Invoked!!!");
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    //捕捉发生的异常
    public void exceptionCaught( ChannelHandlerContext ctx , Throwable cause){
        cause.printStackTrace();
        ctx.close();
    }
}

1.8.2 Client代码

//测试结果
channelActive Invoked!!!!!
Client received:Netty rocks
public class EchoClient {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .remoteAddress("127.0.0.1", 8888)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new EchoClientHandler());
                        }
                    });
            ChannelFuture f = b.connect().sync();
            f.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully().sync();
        }
    }
}
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf>{

    @Override
    public void channelActive( ChannelHandlerContext ctx){
        System.out.println("channelActive Invoked!!!!!");
        ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks", CharsetUtil.UTF_8));
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        System.out.println("Client received:"+byteBuf.toString(CharsetUtil.UTF_8));
    }

    @Override
    public  void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
        cause.printStackTrace();
        ctx.close();
    }
}
posted @ 2017-08-07 16:29  Desneo  阅读(339)  评论(0编辑  收藏  举报