分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 网页技术

初识Netty -- 基于Netty的DayTime时间服务器

发布时间:2023-09-06 01:19责任编辑:傅花花关键词:暂无标签

1. 关于Netty的基本认知:

在JDK 1.4推出Java NIO之前,基于Java的所有Socket通信都采用的BIO(同步阻塞式IO),同步阻塞式IO存在巨大的性能和可靠性瓶颈,无法适用于高性能服务器的开发。虽然后来出现了伪异步I/O通信框架,但它仅仅是对之前I/O线程模型的一个简单优化。    

在JDK 1.4之后,Java诞生了NIO,也就是引入了java.nio类库,提供了很多进行异步I/O开发的API。随着java NIO的发展,对于高性能的服务器开发来说,java原生NIO仍然存在许多问题,甚至出现了非常严重的epoll bug。另外Java原生NIO的API类库繁杂,上手难度大,并非开发者心中理想的框架。

Netty是业界最流行的NIO框架之一,它经历的大规模的商业应用考验,在互联网、大数据、网络游戏等众多行业已经得到了成功商用,因此Netty逐渐成为了Java NIO编程的首选框架。650) this.width=650;" src="https://s1.51cto.com/oss/201710/24/1880b736e188d9a543a773cb8fbbae81.png" title="growup.png" alt="4bab13dc77a97aadcba84ceeae311171.png-wh_" />


2. Netty开发环境搭建

可以使用maven自动构建java项目,本例中只需一个netty jar包,手动导入即可。

下载Netty jar包并导入Java项目中。Netty jar包到http://netty.io/ (netty官网)的download页面,本例中就使用最新的netty-4.1.16.Final,在解压之后的文件夹中找到netty-all-4.1.16.Final.jar,路径netty-4.1.16.Final > jar > all-in-one 。

650) this.width=650;" src="https://s4.51cto.com/oss/201710/24/b2a5620c2bbb7d7e894326bc0c379bdf.png" title="jar.png" alt="e9c1f8988b162995dc896edad51ac879.png-wh_" />

在java项目中创建lib文件夹,导入netty jar包(jar包要作为库文件导入)。

650) this.width=650;" src="https://s2.51cto.com/oss/201710/24/f7b1c12822a99c7e5ba87fc0f306bd9d.png-wh_500x0-wm_3-wmp_4-s_440070410.png" title="importjar.png" alt="f7b1c12822a99c7e5ba87fc0f306bd9d.png-wh_" />

本例中需要创建两个项目,分别是时间服务器和时间客户端。

650) this.width=650;" src="https://s4.51cto.com/oss/201710/24/57185625de3569f8358180d3a6973e6d.png-wh_500x0-wm_3-wmp_4-s_80407975.png" title="project.png" alt="57185625de3569f8358180d3a6973e6d.png-wh_" />


3. 基于Netty的DayTime时间服务器与客户端架构

DayTime服务器只需一个Server启动类和一个业务逻辑处理类(处理客户端请求)即可,客户端也只需一个Client启动类和一个业务逻辑处理类(向服务器发送请求并处理服务器响应),参考下图。

650) this.width=650;" src="https://s1.51cto.com/oss/201710/24/bd85935d74d2a84cb417e75292dc57de.png-wh_500x0-wm_3-wmp_4-s_1913999126.png" title="struct.png" alt="80ed3421ffff79b809e454298b817f13.png-wh_" />

①TimeServer.java(服务器启动类)源码如下:

650) this.width=650;" src="https://s1.51cto.com/oss/201710/24/437d845f346e1624ec65154ac4c37308.png" title="TimeServer.png" alt="4dbf0408cc6dcfd08f91f92974b2e006.png-wh_" />

--------------------------------------------------------------------------------------------------------------------

public class TimeServer {


    public void bind(int port) throws Exception {

        //配置服务端NIO线程组。

        EventLoopGroup bossGroup = new NioEventLoopGroup();

        EventLoopGroup workerGroup = new NioEventLoopGroup();


        try {

            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap.group(bossGroup, workerGroup)

                    .channel(NioServerSocketChannel.class)

                    .option(ChannelOption.SO_BACKLOG, 1024)

                    .childHandler(new ChildChannelHandler());

            //绑定端口,同步等待成功。

            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();

            //等待服务端监听端口关闭。

            channelFuture.channel().closeFuture().sync();

        } finally {

            //优雅退出,释放线程池资源。

            bossGroup.shutdownGracefully();

            workerGroup.shutdownGracefully();

        }

    }

--------------------------------------------------------------------------------------------------------------------

②TimeServerHandler.java(处理客户端请求)源码如下:

650) this.width=650;" src="https://s5.51cto.com/oss/201710/24/bd3fdba781b31b1142ba71b406c454f0.png" title="TimeServerHandler.png" alt="7a4c1b3c632e28e54abda5cef0431ce7.png-wh_" />

--------------------------------------------------------------------------------------------------------------------

public class TimeServerHandler extends ChannelInboundHandlerAdapter {

    @Override

    public void channelRead(ChannelHandlerContext channelHandlerContext, Object msg)

            throws Exception {

        ByteBuf buf = (ByteBuf) msg;

        byte[] req = new byte[buf.readableBytes()];

        buf.readBytes(req);

        String body = new String(req, "UTF-8");

        System.out.println("时间服务器收到请求:" + body);

        String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(

                System.currentTimeMillis()).toString() : "BAD ORDER";

        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());

        channelHandlerContext.write(resp);

    }


    @Override

    public void channelReadComplete(ChannelHandlerContext channelHandlerContext)

            throws Exception {

        channelHandlerContext.flush();

    }


    @Override

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        ctx.close();

    }

}

--------------------------------------------------------------------------------------------------------------------

③TimeClient.java(客户端启动类)源码如下(流程与服务器启动类类似):

650) this.width=650;" src="https://s5.51cto.com/oss/201710/24/ffec04281074136c4c82e4d7bf5668d3.png" title="TimeClient.png" alt="4dbae328d4a52a0c18d26c9a5953fe43.png-wh_" />

--------------------------------------------------------------------------------------------------------------------

public class TimeClient {

    public void connect(int port, String host) throws Exception {

        //配置客户端NIO线程组。

        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try {

            Bootstrap bootstrap = new Bootstrap();

            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)

                    .option(ChannelOption.TCP_NODELAY, true)

                    .handler(new ChannelInitializer<SocketChannel>() {

                        @Override

                        protected void initChannel(SocketChannel socketChannel) throws Exception {

                            socketChannel.pipeline().addLast(new TimeClientHandler());

                        }

                    });


            //发起异步连接操作。

            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();


            //等待客户端链路关闭。

            channelFuture.channel().closeFuture().sync();

        } finally {

            //优雅推出,释放NIO线程组。

            eventLoopGroup.shutdownGracefully();

        }

    }


    public static void main(String[] args) throws Exception {

        int port = 8080;

        if (args != null && args.length > 0) {

            try {

                port = Integer.valueOf(args[0]);

            } catch (NumberFormatException e) {

                //采用默认值。

            }

        }

        new TimeClient().connect(port, "127.0.0.1");

    }

}

--------------------------------------------------------------------------------------------------------------------

④TimeClientHandler.java(客户端业务逻辑处理类)源码如下:

650) this.width=650;" src="https://s3.51cto.com/oss/201710/24/1ab71ef9c680191a05a32cecafd95339.png" title="TimeClientHandler.png" alt="439462e03d2b022472f40818da7cabab.png-wh_" />

--------------------------------------------------------------------------------------------------------------------

public class TimeClientHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = Logger

            .getLogger(TimeClientHandler.class.getName());


    private final ByteBuf firstMessage;


    public TimeClientHandler() {

        byte[] request = "QUERY TIME ORDER".getBytes();

        firstMessage = Unpooled.buffer(request.length);

        firstMessage.writeBytes(request);

    }


    @Override

    public void channelActive(ChannelHandlerContext ctx) {

        ctx.writeAndFlush(firstMessage);

    }


    @Override

    public void channelRead(ChannelHandlerContext ctx, Object msg)

            throws Exception {

        ByteBuf byteBuf = (ByteBuf) msg;

        byte[] req = new byte[byteBuf.readableBytes()];

        byteBuf.readBytes(req);

        String body = new String(req, "UTF-8");

        System.out.println("Now is:" + body);

    }


    @Override

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

        // 释放资源

        logger.warning("Unexpected exception from downstream : " + cause.getMessage());

        ctx.close();

    }

}

--------------------------------------------------------------------------------------------------------------------

4. 启动服务器,运行客户端

先启动服务器,然后运行客户端,此时服务收到客户端的获取时间的请求“QUERY TIME ORDER”,会在控制台输出。客户端此时会接收到服务器响应消息,也就是当前服务器时间。

650) this.width=650;" src="https://s5.51cto.com/oss/201710/24/1c84eced66b82a338d709963524d002f.png-wh_500x0-wm_3-wmp_4-s_491989343.png" title="result.png" alt="1c84eced66b82a338d709963524d002f.png-wh_" />


本文出自 “一赫。” 博客,谢绝转载!

初识Netty -- 基于Netty的DayTime时间服务器

原文地址:http://consolas.blog.51cto.com/9388583/1975711

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved