资讯专栏INFORMATION COLUMN

Netty 服务端开发

luxixing / 2778人阅读

摘要:上一篇文章伪异步和我们使用的原生类库进行异步的开发现在我们使用来进行开发示例代码绑定端口同步等待成功等待服务端监听端口关闭创建两个实例是个线程组它包含了一组线程专门用于网络事件的处理实际上它们就是线程组这里创建两个的原因是一个用于服务端接

上一篇文章 BIO、伪异步 IO、AIO和NIO 我们使用 JDK 的 NIO 原生类库进行异步 IO 的开发. 现在我们使用 Netty 来进行开发.

示例代码
public class TimeServer {

    public void bind(int port) throws Exception {

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChildChannelHandler());

            // 绑定端口, 同步等待成功
            ChannelFuture f = b.bind(port).sync();

            // 等待服务端监听端口关闭
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class ChildChannelHandler extends ChannelInitializer {

        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new TimeServerHandler());
        }
    }

    private class TimeServerHandler extends ChannelHandlerAdapter {
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf buffer = (ByteBuf) msg;
            byte[] req = new byte[buffer.readableBytes()];
            buffer.readBytes(req);

            String body = new String(req, "UTF-8");
            System.out.println(body);

            ByteBuf resp = Unpooled.copiedBuffer("6666".getBytes());
            ctx.write(resp);
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
        }
    }

}

创建两个 NioEventLoopGroup 实例. NioEventLoopGroup 是个线程组, 它包含了一组 NIO 线程, 专门用于网络事件的处理, 实际上它们就是 Reactor 线程组. 这里创建两个的原因是一个用于服务端接收客户端的连接, 另一个用于进行 SocketChannel 的网络读写.

创建 ServerBootstrap 对象, 它是 Netty 用于启动 NIO 服务端的辅助启动类, 目的是降低服务端的开发复杂度.

调用 ServerBootstrapgroup 方法, 将两个 NIO 线程组当作参数传递到 ServerBootstrap 中. 并且设置 Channel 为 NioServerSocketChannel, 它的功能对于 JDK NIO 类库中的 ServerSocketChannel 类. 然后配置 NioServerSocketChannel 的 TCP 参数, 此处将它的 backlog 设置为 1024. 最后绑定 IO 事件的处理类 ChildChannelHandler, 它的作用类似于 Reactor 模式中的 Handler 类, 主要用于处理网络 IO 事件, 例如记录日志, 对消息进行编解码等.

ChannelOption.SO_BACKLOG 对应的是 tcp/ip 协议 listen 函数中的 backlog 参数, 函数 listen(int socketfd,int backlog) 用来初始化服务端可连接队列, 服务端处理客户端连接请求是顺序处理的, 所以同一时间只能处理一个客户端连接, 多个客户端来的时候, 服务端将不能处理的客户端连接请求放在队列中等待处理, backlog参数指定了队列的大小. ChannelOption 连接

服务端启动辅助类配置完成之后, 调用它的 bind 方法绑定监听端口, 随后, 调用同步阻塞方法 sync 等待绑定操作完成. 完成之后 Netty 会返回一个 ChannelFuture, 它的功能类似于 JDK 的 java.util.concurrent.Future, 主要用于异步操作的通知回调.

f.channel().closeFuture().sync(); 方法进行阻塞, 等待服务端链路关闭之后 main 函数才退出.

调用 NIO 线程组的 shutdownGracefully 进行优雅退出, 它会释放跟 shutdownGracefully 相关联的资源.

TimeServerHandler 继承自 ChannelHandlerAdapter, 它用于对网络事件进行读写操作, 通常我们只需要关注 channelReadexceptionCaught 方法.

channelRead 方法中, 将 msg 转换成 Netty 的 ByteBuf 对象. ByteBuf 类似与 JDK 中的 java.nio.ByteBuffer 对象, 不过它提供了更加强大和灵活的功能. 通过 ByteBufreadableBytes 方法可以获取缓冲区可读的字节数. 然后使用 readBytes 方法将缓冲区中的字节数组复制到新建的 byte 数组中.

我们还调用了 ChannelHandlerContextflush 方法, 它的作用是将消息发送队列中的消息写入到 SocketChannel 中发送给对方. 从性能角度考虑, 为了防止频繁的唤醒 Selector 进行消息发送, Netty 的 write 方法并不直接将消息写入 SocketChannel 中.

注意: write 方法只是将要发送的消息放到消息发送队列中, 再通过调用 flush 方法, 将发送缓冲区中的消息全部写到 SocketChannel 中.

exceptionCaught 方法中, 如果出现异常, 就关闭 ChannelHandlerContext, 释放和 ChannelHandlerContext 相关联的句柄等资源.

总结

EventLoopGroup: 线程组, 专门用于网络事件的处理, 实际上它们就是 Reactor 线程组.
ServerBootstrap 是 Netty 用于启动 NIO 服务端的辅助启动类.
group方法: 第一个参数 parent (acceptor), 第二个参数 child (client).
NioServerSocketChannel: 它的功能对于 JDK NIO 类库中的 ServerSocketChannel 类.
ServerSocketChannel: 允许我们监听TCP链接请求, 每个请求会创建会一个 SocketChannel.
ChannelHandlerAdapter类: 它用于对网络事件进行读写操作.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72718.html

相关文章

  • netty搭建web聊天室(1)

    摘要:提供异步的事件驱动的网络应用程序框架和工具,用以快速开发高性能高可靠性的网络服务器和客户端程序。总结我们完成了服务端的简单搭建,模拟了聊天会话场景。 之前一直在搞前端的东西,都快忘了自己是个java开发。其实还有好多java方面的东西没搞过,突然了解到netty,觉得有必要学一学。 介绍 Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框...

    izhuhaodev 评论0 收藏0
  • Netty4.x 源码实战系列(一):ServerBootstrap 与 Bootstrap 初探

    摘要:而用于主线程池的属性都定义在中本篇只是简单介绍了一下引导类的配置属性,下一篇我将详细介绍服务端引导类的过程分析。 从Java1.4开始, Java引入了non-blocking IO,简称NIO。NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念。传统的socket是基于stream的,它是单向的,有InputStream表示read和Outpu...

    BakerJ 评论0 收藏0
  • 慕课网_《Netty入门之WebSocket初体验》学习总结

    时间:2018年04月11日星期三 说明:本文部分内容均来自慕课网。@慕课网:https://www.imooc.com 教学源码:https://github.com/zccodere/s... 学习源码:https://github.com/zccodere/s... 第一章:课程介绍 1-1 课程介绍 什么是Netty 高性能、事件驱动、异步非阻塞的IO Java开源框架 基于NIO的客户...

    Noodles 评论0 收藏0
  • 牛啤~这个框架被大量使用,腾讯开源的RPC框架阿里的Dubbo全靠它

    摘要:分布式高并发微服务问阿里京东蚂蚁等大厂面试真题解析道跳槽涨薪必备精选面试题最新版大厂面试真题集点击这里免费领取点击这里免费领取 估计很多Java程序员平时主要的工作就是一些Web系统的业务开发,对于服务端IO程序以及网络通信编程做得并不多,但是对于高级或者资深程序员来说,IO通信以及服务端编...

    whidy 评论0 收藏0

发表评论

0条评论

luxixing

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<