Netty简单的入门代码示例
作者:Colins~
这篇文章主要介绍了Netty简单的入门代码示例,Netty 的内部实现是很复杂的,但是 Netty 提供了简单易用的API从网络处理代码中解耦业务逻辑,Netty 是完全基于 NIO 实现的,所以整个 Netty 都是异步的,需要的朋友可以参考下
前言
纯Java几种网络IO的开发步骤及示例,毫无疑问最好的就是NIO,这也是目前最主流的方式,但是这玩意编写复杂,拓展性也不强,在通信上方方面面都需要重写,这不是一般人能搞得定了,所以呀我们得会用框架呀,Netty就是这方面框架中的佼佼者!
基础示例入门
服务端
NettyServer.class
@Slf4j public class NettyServer{ //1.创建线程组 bossGroup:连接线程 workGroup:工作线程 private final NioEventLoopGroup bossGroup = new NioEventLoopGroup(); private final NioEventLoopGroup workerGroup = new NioEventLoopGroup(); public void serverStart() throws InterruptedException { try{ // 服务端启动类 ServerBootstrap bootstrap = new ServerBootstrap(); // 传入两个线程组 bootstrap.group(bossGroup, workerGroup) // 指定Channel 和NIO一样是采用Channel通道的方式通信 所以需要指定服务端通道 .channel(NioServerSocketChannel.class) //使用指定的端口设置套接字地址 .localAddress(new InetSocketAddress(11111)) //服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数 .option(ChannelOption.SO_BACKLOG, 1024) //设置数据处理器 .childHandler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel channel) throws Exception { // 在管道中 添加数据处理类 channel.pipeline().addLast(new NettyServerTestHandler()); } }); // 同步等待成功 ChannelFuture future = bootstrap.bind().sync(); if (future.isSuccess()) { log.info("启动 Netty Server 成功"); } //等待服务端监听端口关闭 链路关闭后main函数才会结束 future.channel().closeFuture().sync(); }finally { // 优雅的关闭 释放资源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { new NettyServer().serverStart(); } }
看上去好多,感觉比NIO还麻烦?其实很方便的:
- 实例化一个服务端 ServerBootstrap ,这个NIO也一样,Netty帮我们封装了
- 设置两个线程组,一个处理客户端连接事件,一个处理连接后数据处理事件
- 指定服务端通道类型,并绑定地址
- 设置传输的一些配置参数(这里有很多可以设置,所以拓展性强)
- 设置数据处理器,这里实际是添加了一个数据处理管道,管道内可以有很多数据处理类,所以可以一层一层处理,可插拔式设计(类似拦截器链)
channel.pipeline() : 这就是管道 new NettyServerTestHandler() : 这个就是管道里的一个数据处理类 // 数据处理类可以有多个
- 最后启动
ServerBootstrap 实例化后,都是采用建造者模式设置的,对于我们来说是非常的方便的,这里配置好后我们的重心就可以放在数据处理类上了
NettyServerTestHandler.class
NettyServerTestHandler 就是数据处理类,所有的方法都帮我们封装好了,我们不需要考虑其中调用的问题,方法是处理什么事件的,我们写对应的逻辑就好了,方法上的ChannelHandlerContext 可以理解为管道中所有数据处理类的纽带,比如拦截器链不也有么
@Slf4j public class NettyServerTestHandler extends ChannelInboundHandlerAdapter { // 读取信息调用 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 和NIO一样有缓冲区 ByteBuf就是对ByteBuffer做了一层封装 ByteBuf msg1 = (ByteBuf) msg; log.info("客户端信息:" + msg1.toString(CharsetUtil.UTF_8)); } // 连接事件 连接成功调用 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { SocketAddress socketAddress = ctx.channel().remoteAddress(); log.info(socketAddress + " 已连接"); // 发送数据 ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Client", CharsetUtil.UTF_8)); } // 断开连接调用 @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { log.info(ctx.channel().remoteAddress() + " 已断开连接"); } // 读取信息完成事件 信息读取完成后调用 @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } // 异常处理 发生异常调用 @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 异常后 关闭与客户端连接 ctx.close(); } }
客户端
NettyClient.class
客户端启动和服务端几乎一致,只不过启动类成了Bootstrap ,而且我还加入了一个断连逻辑
@Slf4j public class NettyClient { private EventLoopGroup group = new NioEventLoopGroup(); private int port=11111; private String host="127.0.0.1"; public void start() throws InterruptedException { try{ Bootstrap bootstrap = new Bootstrap(); // 客户端不需要处理连接 所以一个线程组就够了 bootstrap.group(group) // 连接通道 .channel(NioSocketChannel.class) .remoteAddress(host, port) .option(ChannelOption.TCP_NODELAY, true) // 数据处理 .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel channel) throws Exception { channel.pipeline().addLast(new NettyClientTestHandler()); } }); ChannelFuture future = bootstrap.connect(); //客户端断线重连逻辑 future.addListener((ChannelFutureListener) future1 -> { if (future1.isSuccess()) { log.info("连接Netty服务端成功"); } else { log.info("连接失败,进行断线重连"); future1.channel().eventLoop().schedule(() -> { try { start(); } catch (InterruptedException e) { e.printStackTrace(); } }, 20, TimeUnit.SECONDS); } }); future.channel().closeFuture().sync(); }catch (Exception e){ log.info("服务端异常"); }finally { group.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { new NettyClient().start(); } }
NettyClientTestHandler.class
数据处理类也是一样的
@Slf4j public class NettyClientTestHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf msg1 = (ByteBuf) msg; log.info("服务端信息:" + msg1.toString(CharsetUtil.UTF_8)); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 连接上 就给服务端发送数据 ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Server", CharsetUtil.UTF_8)); SocketAddress socketAddress = ctx.channel().remoteAddress(); log.info(socketAddress + " 已连接"); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { log.info(ctx.channel().remoteAddress() + " 已断开连接"); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }
到此这篇关于Netty简单的入门代码示例的文章就介绍到这了,更多相关Netty入门代码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!