Spring架构篇--2.7 远程通信基础--使用Netty

Netty是一个基于JavaNIO的高性能网络通信框架,简化了TCP和UDP服务器的开发。它提供了异步事件驱动的API,支持多路复用,通过Channel、EventLoop、ChannelHandler等组件实现高效网络编程。文章通过示例展示了Netty服务端和客户端的创建,强调了Netty的简单API、零拷贝优化以及多语言和多协议支持的特点。
摘要由CSDN通过智能技术生成

前言:Netty 作为Nio 模型的实现,相较于Selector ,进一步将api进行封装,使用更加的简单;在平常的开发中会发现许多组件的底层通信都使用了Netty,所以就非常有必要对Netty 的使用以及其工作原理进行了解了。

1 Netty介绍:

Netty是一个NIO基于事件驱动的客户端服务器框架,可以快速轻松地开发网络应用程序,例如协议服务器和客户端。它极大地简化和简化了网络编程,如TCP和UDP套接字服务器开发。
它是一个高性能、异步事件驱动的网络编程框架,它基于Java NIO(New I/O)开发,提供了一种简单易用的API,使得开发者能够轻松地构建高性能、可扩展的网络应用程序。Netty的设计目标是提供一个可嵌入、高性能、灵活、易于使用的网络编程框架,支持多种传输协议,如TCP、UDP、HTTP、WebSocket等,并且提供了丰富的功能,如SSL/TLS支持、压缩、编解码、流量控制、负载均衡、连接管理等。
Netty的核心组件包括:Channel、EventLoop、ChannelFuture、ChannelHandler和Bootstrap等。其中,Channel是网络通信的载体,EventLoop是异步事件驱动的核心,ChannelFuture是异步操作的结果,ChannelHandler是处理网络事件的组件,Bootstrap则是启动Netty应用程序的入口点。
Netty的优点在于其高性能、可扩展性和灵活性。它采用了异步非阻塞的IO模型,能够处理大量并发连接,同时提供了丰富的功能和扩展性,可以通过自定义ChannelHandler来实现各种业务逻辑。此外,Netty具有良好的文档和社区支持,能够在开发过程中提供及时的帮助和支持。

2 netty 使用:

2.1 服务端:
1)netty 服务端:

package org.lgx.bluegrass.bluegrasscoree.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.lgx.bluegrass.bluegrasscoree.netty.hadler.DiscardServerHandler;

/**
 * @Description TODO
 * @Date 2023/3/13 16:49
 * @Author lgx
 * @Version 1.0
 */
public class DiscardServer {

    private int port;

    public DiscardServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) {
        new DiscardServer(8080).run();
    }

    private void run() {
    	// 总线程
        NioEventLoopGroup boss = new NioEventLoopGroup();
        // 工作线程
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
        	//netty 服务端
            ServerBootstrap server = new ServerBootstrap();
             // 服务端参数
            server.group(boss,worker)
            		  // nio socket 处理
                    .channel(NioServerSocketChannel.class)
                     // 子线程事件回调处理
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new DiscardServerHandler());
                        }
                    })
                     // 主线程最大的分配线程数
                    .option(ChannelOption.SO_BACKLOG,128)
                      // 保持长连接
                    .childOption(ChannelOption.SO_KEEPALIVE,true);
             // 启动服务
            ChannelFuture f = server.bind(this.port).sync();
             System.out.println("8080服务已启动");
              // 关闭通道
            f.channel().closeFuture().sync();
              
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
        	// 线程关闭
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

2) 事件处理 Handler:

package org.lgx.bluegrass.bluegrasscoree.netty.hadler;


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

/**
 * @Description TODO
 * @Date 2023/3/13 16:38
 * @Author lgx
 * @Version 1.0
 */
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // super.channelRead(ctx, msg);
        // ((ByteBuf) msg).release();
        // ByteBuf in = (ByteBuf) msg;
        // try {
        //     while (in.isReadable()) { // (1)
        //         System.out.print((char) in.readByte());
        //         System.out.flush();
        //     }
        // }finally {
        //     ReferenceCountUtil.release(msg);
        // }
        ctx.write(msg); // (1)
        ctx.flush(); // (2)
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // super.exceptionCaught(ctx, cause);
        cause.printStackTrace();
        ctx.close();
    }
}

2.2 客户端:
1) 客户端连接

package org.lgx.bluegrass.bluegrasscoree.netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.lgx.bluegrass.bluegrasscoree.netty.hadler.ClientHandler;


/**
 * @Description TODO
 * @Date 2023/3/13 17:17
 * @Author lgx
 * @Version 1.0
 */
public class Client {
    private int port;

    public Client(int port) {
        this.port = port;
    }

    public static void main(String[] args) {
        new Client(8080).run();
    }

    private void run() {
    	// 工作线程
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
        	// netty 客户端
            Bootstrap b = new Bootstrap();
            b.group(worker)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new ClientHandler());
                        }
                    });

            ChannelFuture f = b.connect("localhost",this.port).sync();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            worker.shutdownGracefully();

        }
    }
}

  1. 事件处理Handler:
package org.lgx.bluegrass.bluegrasscoree.netty.hadler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

/**
 * @Description TODO
 * @Date 2023/3/13 17:21
 * @Author lgx
 * @Version 1.0
 */
public class ClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // super.channelRead(ctx, msg);
        ByteBuf in = (ByteBuf) msg;
        try {
            while (in.isReadable()) { // (1)
                System.out.print((char) in.readByte());
                System.out.flush();
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // super.exceptionCaught(ctx, cause);
        cause.printStackTrace();
        ctx.close();
    }
}

Netty 中对于其 配置的参数如ChannelOption.SO_KEEPALIVE,ChannelOption.SO_BACKLOG等,在后续对ServerBootstrap 进行解读时在进行探究;

3 netty 特点:

3.1 netty 解决Selector的使用不便:
Nio 模式,实现多路复用,一个线程监听,采用事件回调机制,处理多个客户端的数据传输;虽然使用selector 可以实现多路复用,但是需要自己进行注册的维护,轮训,对管道数据的读写也比较麻烦;

3.2 netty 的api流程简单:
服务端:
在这里插入图片描述

客户端:
在这里插入图片描述
3.3 零拷贝:netty 在接收到数据后,可以直接将数据在系统空间进行处理,并且通过系统空间写会到管道中;
1、接收和发送ByteBuffer使用堆外直接内存进行Socket读写;
2、提供了组合Buffer对象,可以聚合多个ByteBuffer对象;
3、transferTo0直接将文件缓冲区的数据发送到目标Channel;

3.4 提前分配后数据要存放的内存空间,并且可以反复利用;
3.5 责任链串行设计(连过长一定程度影响性能)
在这里插入图片描述
3.6 Netty 支持多语言,多协议;高性能序列化;

4 参考:
1 Netty 4.x 版用户指南;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值