netty学习系列(一)netty初体验

来源:互联网 发布:nginx重启 编辑:程序博客网 时间:2024/05/24 07:32

前言

男票做需求用到了netty这个nio框架,于是我挺身而出学习netty的使用和源码。后续netty会总结一个系列,对netty进行源码级的详细分析,敬请期待。首先祭上第一篇,netty初体验。

目录

  • netty概述
  • 使用示例
  • 关键组件简述
  • -

netty是什么

对于这个问题netty的官网上有两种表述,可以综合起来看下netty是什么

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.

Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients.

总结一下,netty是异步的 事件驱动的基于NIO实现的开源框架,用以快速轻松的实现高性能、高可靠性的网络客户端和服务器程序。

附一篇链接《Java NIO通信框架在电信领域的实践》

http://www.infoq.com/cn/articles/practice-of-java-nio-communication-framework/

使用示例

在这个小例子里简单实现了一下netty客户端服务端,进行通信,在服务端定义了两个自己的handler,根据客户端发送的数据的特点,决定是否传递给下一个handler处理

  • 服务端代码
package netty.echo;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.ChannelPipeline;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.codec.serialization.ClassResolvers;import io.netty.handler.codec.serialization.ObjectDecoder;import io.netty.handler.codec.serialization.ObjectEncoder;public class NettyServer {        public static void main(String[] args) throws Exception {            EventLoopGroup bossGroup = new NioEventLoopGroup(1);            EventLoopGroup workerGroup = new NioEventLoopGroup();            try {                ServerBootstrap b = new ServerBootstrap();                b.group(bossGroup, workerGroup)                 .channel(NioServerSocketChannel.class)                 .option(ChannelOption.SO_BACKLOG, 100)                 .childHandler(new ChannelInitializer<SocketChannel>() {                     @Override                     public void initChannel(SocketChannel ch) throws Exception {                         ChannelPipeline p = ch.pipeline();                         p.addLast(new ObjectEncoder(),new ObjectDecoder(ClassResolvers.cacheDisabled(null)),new ServerHandler1());                         p.addLast(new ServerHandler2());                     }                 });                // Start the server.                ChannelFuture f = b.bind(8007).sync();                // Wait until the server socket is closed.                f.channel().closeFuture().sync();            } finally {                // Shut down all event loops to terminate all threads.                bossGroup.shutdownGracefully();                workerGroup.shutdownGracefully();            }        }}

ServerHandler1

package netty.echo;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;public class ServerHandler1 extends ChannelInboundHandlerAdapter        implements ChannelHandler {        @Override        public void channelRead(ChannelHandlerContext ctx, Object msg) {            int temp = (Integer)msg;            if(temp % 2 == 0){                System.out.println("handler1 ------"+temp+ "是偶数,继续调用下个handler");                ctx.fireChannelRead(msg);            }else{                System.out.println("handler1 ------"+temp+ "是奇数,直接返回");                ctx.write("奇数");            }        }        @Override        public void channelReadComplete(ChannelHandlerContext ctx) {            ctx.flush();        }        @Override        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {            cause.printStackTrace();            ctx.close();        }}

ServerHandler2

package netty.echo;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;public class ServerHandler2 extends ChannelInboundHandlerAdapter implements        ChannelHandler {    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) {        System.out.println("handler2 ------" + msg);        ctx.write("偶数");    }    @Override    public void channelReadComplete(ChannelHandlerContext ctx) {        ctx.flush();    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        cause.printStackTrace();        ctx.close();    }}
  • 客户端代码
package netty.echo;import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.ChannelPipeline;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;import io.netty.handler.codec.serialization.ClassResolvers;import io.netty.handler.codec.serialization.ObjectDecoder;import io.netty.handler.codec.serialization.ObjectEncoder;public class NettyClient {        static final String HOST = System.getProperty("host", "127.0.0.1");        static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));        public static void main(String[] args) throws Exception {            EventLoopGroup group = new NioEventLoopGroup();            try {                Bootstrap b = new Bootstrap();                b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)                    .handler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ChannelPipeline p = ch.pipeline();                            p.addLast(new ObjectEncoder(), new ObjectDecoder(ClassResolvers.cacheDisabled(null)),                                new ClientHandler1());                        }                    });                ChannelFuture f = b.connect(HOST, PORT).sync();                f.channel().closeFuture().sync();            }            finally {                group.shutdownGracefully();            }        }}

ClientHandler1

package netty.echo;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;public class ClientHandler1 extends ChannelInboundHandlerAdapter        implements ChannelHandler {    private final Integer msg = 33;    private static int i = 0;    /**     * Creates a client-side handler.     */    public ClientHandler1() {    }    @Override    public void channelActive(ChannelHandlerContext ctx) {        ctx.writeAndFlush(msg);    }    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) {        System.out.println(msg);        if( i < 10 ){             ctx.write(i++);        }    }    @Override    public void channelReadComplete(ChannelHandlerContext ctx) {        ctx.flush();    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        // Close the connection when an exception is raised.        cause.printStackTrace();        ctx.close();    }}
  • 执行结果

handler1 ——33是奇数,直接返回
handler1 ——0是偶数,继续调用下个handler
handler2 ——0
handler1 ——1是奇数,直接返回
handler1 ——2是偶数,继续调用下个handler
handler2 ——2
handler1 ——3是奇数,直接返回
handler1 ——4是偶数,继续调用下个handler
handler2 ——4
handler1 ——5是奇数,直接返回
handler1 ——6是偶数,继续调用下个handler
handler2 ——6
handler1 ——7是奇数,直接返回
handler1 ——8是偶数,继续调用下个handler
handler2 ——8
handler1 ——9是奇数,直接返回

关键组件简述

从上面的例子中可以看到netty的几个核心的东西Bootstrap、EventLoopGroup、NioSocketChannel、ChannelPipeline、Handler。下面从我的理解上简单说下这几个核心组件的作用,后续会针对每个组件进行详细的源码分析。

Bootstrap
bootstrap是辅助的意思,我的理解它是netty的一个总管,负责维护管理其他各核心部分。不知道准不准确,后面会深入的看一下。

NioServerSocketChannel

private final SelectableChannel ch;  

我的理解是netty的channel是对nio channel的封装,eventloop是对selector的封装
从AbstractNioChannel这个类中已经可以看到netty的channel是如何和socket 的nio channel关联的了,以及channel是如何和eventloop关联的。

EventLoopGroup
从名字上看它肯定和netty的事件驱动有关。
EventLoopGroup是一个处理I/O操作的多线程事件环,更直白的说是一个线程池,它由一个或多个EventLoop来构成,是EventLoop的容器。

在上面的代码实例中,一开始就是下面的几句

    EventLoopGroup bossGroup = new NioEventLoopGroup(1);    EventLoopGroup workerGroup = new NioEventLoopGroup();         try {             ServerBootstrap b = new ServerBootstrap();             b.group(bossGroup, workerGroup)

在Server端的Bootstrap参数中,有两个EventLoopGroup,第一个通常称为’boss’,用于接收发来的连接请求。第二个称为’worker’,,用于处理boss接受并且注册给worker的连接中的信息。

NioEventLoop

Selector selector;  private SelectedSelectionKeySet selectedKeys;

在这里类里我们看到了nio的核心的selector和selectedKeys。
是对selector的封装。

从这几个数据属性和代码可以看出这时netty开始调用JDK的Socket函数,包括我们熟悉的selector和key。也就是说真正调用底层socket的地方是在NioEventLoop中。

pipleline
是操作处理的入口,是ChannelHandler的管理者,提供了很多方法对handler进行操作。每个Channel都有一个对应的pipeline,每个pipeline有两个ChannelHandlerContext,分别包含默认的TailHandler和HeadHandler,并且它们构成一个双向链表结构。TailHandler处理inbound类型的数据;HeadHandler处理outbound类型的数据。利用ChannelHandlerContext上下文获取Handler,然后间接调用Handler的函数实现处理逻辑

ChannelHandler

而我们可以在handler里定义具体的操作。我们可以根据具体的判断是透传这个信息给下一个handler,还是自己进行处理。

0 0
原创粉丝点击