Netty框架

1.Netty的简介

Netty是一个高性能,异步事件驱动的NIO框架,他提供了对TCP、UDP和文件传输的支持。使用更高效的 socket 底层,对epoll空轮询引起的cpu占用飙升在内部进行了处理,避免直接使用NIO陷阱,简化了NIO处理的方式。
采用多种decoder/encoder支持,对TCP粘包/分包进行自动化处理。可接受处理线程池,提高连接效率,对重连,心跳检测的简单支持。可配置IO线程数,TCP参数,TCP接受和发送缓冲区使用直接内存代替堆内存,通过内存池的方式循环利用ByteBuf。使用单线程串行化的方式,高效的Reactor线程模型,大量使用volitale,使用了CAS和院子类,线程安全类的使用,读写锁的使用。

2.Netty的核心组件

Channel:
Channel 是 NIO 基本的结构。它代表了一个用于连接到实体如硬件设备、文件、网络套接字 或程序组件,能够执行一个或多个不同的 I/O 操作(例如读或写)的开放连接。 现在,把 Channel 想象成一个可以“打开”或“关闭”,“连接”或“断开”和作为传入和传出数据的运输 工具。

boorstrap:
Netty应用程序通过设置bootstrap(引导)类的开始,该类提供一个用于应用程序网络层配置的容器

Future
Future 提供了另外一种通知应用操作已经完成的方式。这个对象作为一个异步操作结果的占 位符,它将在将来的某个时候完成并提供结果。
JDK 附带接口 java.util.concurrent.Future ,但所提供的实现只允许您手动检查操作是否完成或 阻塞了。这是很麻烦的,所以 Netty 提供自己了的实现,ChannelFuture,用于在执行异步操作 时使用。

Channel channel = ...;
 //不会阻塞 
 ChannelFuture future = channel.connect( new InetSocketAddress("192.168.0.1", 25));

Callback (回调)
callback (回调)是一个简单的方法,提供给另一种方法作为引用,这样后者就可以在某个合适的 时间调用前者。这种技术被广泛使用在各种编程的情况下,最常见的方法之一通知给其他人操 作已完成。
Netty 内部使用回调处理事件时。一旦这样的回调被触发,事件可以由接口 ChannelHandler 的实现来处理。如下面的代码,一旦一个新的连接建立了,调用 channelActive(),并将打印一条 消息。

public class ConnectHandler extends ChannelInboundHandlerAdapter {
	@Override 
	public void channelActive(ChannelHandlerContext ctx) throws Exception { 
 	//1 System.out.println( "Client " + ctx.channel().remoteAddress() + " connected"); 
	 } 
}

Event 和 Handler
Netty 使用不同的事件来通知我们更改的状态或操作的状态。这使我们能够根据发生的事件触发适当的行为。这些行为可能括: 日志数据转换 流控制 应用程序逻辑 。

由于 Netty 是一个网络框架,事件很清晰的跟入站或出站数据流相关。因为一些事件可能触发 传入的数据或状态的变化包括: 活动或非活动连接 / 数据的读取 / 用户事件 / 错误

出站事件是由于在未来操作将触发一个动作。
这些包括: 打开或关闭一个连接到远程 写或冲刷数据到 socket
每个事件都可以分配给用户实现处理程序类的方法。这说明了事件驱动的范例可直接转换为 应用程序构建块。

下图显示了一个事件可以由一连串的事件处理器来处理
在这里插入图片描述
Netty 的 ChannelHandler 是各种处理程序的基本抽象。想象下,每个处理器实例就是一个回 调,用于执行对各种事件的响应。 在此基础之上,Netty 也提供了一组丰富的预定义的处理程序,您可以开箱即用。比如,各种协 议的编解码器包括 HTTP 和 SSL/TLS。在内部,ChannelHandler 使用事件和 future 本身,创建 具有 Netty 特性抽象的消费者。

Future, CallBack 和 Handler
Netty 的异步编程模型是建立在 future 和 callback 的概念上的。所有这些元素的协同为自己的 设计提供了强大的力量。 拦截操作和转换入站或出站数据只需要您提供回调或利用 future 操作返回的。这使得链操作 简单、高效,促进编写可重用的、通用的代码。一个 Netty 的设计的主要目标是促进“关注点分 离”:你的业务逻辑从网络基础设施应用程序中分离。

Selector, Event 和 EventLoop。
Netty 通过触发事件从应用程序中抽象出 Selector,从而避免手写调度代码。EventLoop 分配 给每个 Channel 来处理所有的事件,包括 注册感兴趣的事件 调度事件到 ChannelHandler 安排进一步行动 该 EventLoop 本身是由只有一个线程驱动,它给一个 Channel 处理所有的 I/O 事件,并且在 EventLoop 的生命周期内不会改变。这个简单而强大的线程模型消除你可能对你的 ChannelHandler 同步的任何关注,这样你就可以专注于提供正确的回调逻辑来执行。该 API 是简单和紧凑。

3.Netty 客户端/服务器 总览

在这里插入图片描述
图中显示了连接到服务器的多个并发的客户端。在理论上,客户端可以支持的连接数只受限 于使用的 JDK 版本中的制约。

4.实现一个简单地Netty连接

服务端:

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        /**
        * 创建两个事件循环组EventLoopGroup
        * 第一个EventLoopGroup的作用接受客户端连接(ACCEPT),将接收到的通道(channel)分配给工作线程处理
        * 第二个EventLoopGroup的作用是主要来接受主EventLoopGroup提交的任务
        * EventLoopGroup实质上是一个线程池,线程池大小默认为
        * EventLoopGroup 事件循环实质是一个for死循环处理:for(;;)
        */
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try{
            //ServerBootStrap服务端启动辅助类,设置启动相关的配置信息
            ServerBootstrap bootstrap = new ServerBootstrap()
                    //将主线程和工作线程传入对应线程组
                    .group(boss, worker)
                    //设置主线程处理的通道实例类
                    .channel(NioServerSocketChannel.class)
                    //处理事件单元
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ServerHandler());
                            pipeline.addLast(new StringDecoder());
                            pipeline.addLast(new StringEncoder());
                        }

                    });
            //同步启动服务端
            ChannelFuture sync = bootstrap.bind(9999).sync();
            //阻塞通道关不
            sync.channel().closeFuture().sync();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

客户端:

public class NettyClient {
    public static void main(String[] args) {
        NioEventLoopGroup loopGroup = new NioEventLoopGroup(1);

        try {
            //启动辅助类
            Bootstrap bootstrap = new Bootstrap()
                    .group(loopGroup)
                    .channel(NioSocketChannel.class)
                    .remoteAddress("127.0.0.1",9999)
                    .handler(new ChannelInitializer <NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ClientHandler());
                            pipeline.addLast(new StringEncoder());
                            pipeline.addLast(new StringDecoder());
                        }
                    });
            //同步阻塞等待连接成功
            ChannelFuture sync = bootstrap.connect().sync();
            //发送消息
            String msg = "hello\n";
            sync.channel().writeAndFlush(msg);

            //同步阻塞关闭客户端连接
            sync.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            loopGroup.shutdownGracefully();
        }

    }
}

ServerHandler:

public class ServerHandler extends SimpleChannelInboundHandler<String> {
    //接收用户发送消息
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel();
        SocketAddress remoteAddress =
                channel.remoteAddress();

        System.out.println("接收消息0:"+remoteAddress+":"+msg);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();

        SocketAddress remoteAddress =
                channel.remoteAddress();
        ByteBuf buf = (ByteBuf) msg;
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);
        String s = new String(bytes);
        channel.writeAndFlush("ACK:"+s);

        System.out.println("接收消息1:"+remoteAddress+":"+s);

    }

    //用户连接上线
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        SocketAddress remoteAddress =
                channel.remoteAddress();

        System.out.println("客户端:"+remoteAddress+" 上线了");

    }

    //用户连接下线
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        SocketAddress remoteAddress =
                channel.remoteAddress();

        System.out.println("客户端:"+remoteAddress+" 下线了");
    }
}

ClientHandler:

public class ClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();

        SocketAddress remoteAddress =
                channel.remoteAddress();
        ByteBuf buf = (ByteBuf) msg;
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);
        String s = new String(bytes);

        System.out.println(s);

    }
}

运行结果:
在这里插入图片描述
在这里插入图片描述

5.为什么要使用Netty?

1.API使用简单,更容易上手,开发门槛低
2.功能强大,预置了多种编码功能,支持多种主流协议
3.定制能力高,可通过ChannelHandler对通信框架进行灵活的扩展
4.高性能,与多种NIO主流框架相比,Netty综合性能更好
5.高稳定性,解决了NIO的Bug
6.经历了大过的商业应用应用考验,质量的可靠性都有很好的验证

6.Netty能提供什么服务?

1.开发异步非阻塞的TCP网络应用程序
2.开发异步非阻塞的UDP网络应用程序
3.开发异步文件传输程序
4.开发HTTP异步程序的服务端和客户端
5.提供多种编码的集成框架,包括谷歌Protobuf、JBossMarshalling、Java序列化、压缩编解码、XML解码、字符串编解码等
6.提供多种形式的编解码基础类库,可以方便的进行私有协议栈编解码框架的二次开发
7.基于职责链的Pipeline-Handler机制,可以方便对网络事件进行拦截
8.所有IO操作都是异步,用户可以通过Future-Listeren机制主动get结果或IO线程完成操作之后主动Notify来通知,用户业务线程不用同步等待
9.基于链路空闲事件检测的心跳机制
10.流量控制和整形

————参考书籍《Netty实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值