一、Netty4教程
Netty4是一款使用Java语言基于NIO框架构建的高性能异步网络通信框架,它提供了一种新的方式在Java平台上开发可扩展的、模块化的、高性能的、可维护的TCP/IP服务器和客户端。Netty4的特点是高性能、高清晰度,易于使用和灵活性。
在Netty4的教程中,我们可以学习如何使用Netty4来编写TCP/IP服务器、客户端和代码示例,如下所示:
public class NettyServer { public static void main(String[] args) throws Exception { //1.创建EventLoopGroup对象,是一个线程池,实际数量可以根据业务需求调整 EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workGroup = new NioEventLoopGroup(); try { //2.创建ServerBootstrap对象,是启动服务的工具类 ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workGroup) //3.设置TCP协议的Channel,NioServerSocketChannel是对java.nio.*包的封装 .channel(NioServerSocketChannel.class) //4.设置对client连接的数据处理逻辑PipeLine .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new NettyServerHandler()); } }) //5.设置TCP连接参数,SO_BACKLOG是指处于同一时刻待处理的连接队列的最大长度,超出的新连接会被拒绝,jvm会抛出ConnectionRefusedException .option(ChannelOption.SO_BACKLOG, 100) //6.设置缓冲区大小,通常可以不设置,会根据操作系统自适应,如果出现流量控制异常,可以考虑增加缓冲区大小 .option(ChannelOption.SO_SNDBUF, 65535) .option(ChannelOption.SO_RCVBUF, 65535) //7.设置心跳检测机制以及关闭保护机制,保证TCP的正常关闭,防止TCP连接个数增长到JVM的最大值时出现宕机和内存耗尽等问题 .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.TCP_NODELAY, true); // Bind and start to accept incoming connections. //8.绑定端口 ChannelFuture f = b.bind(PORT).sync(); //9.监听channel关闭事件并执行shutdownGracefully关闭服务器和事件处理组 f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workGroup.shutdownGracefully(); } } }
二、Netty4 Client Pool
在我们使用Netty4来编写客户端时,为了保证程序的高效性,需要使用连接池来减少重新建立连接带来的开销,使用连接池来管理大量的连接可以提高程序的并发量和性能。
下面是使用Apache Commons Pool结合Netty4实现连接池的代码示例:
public class NettyClientFactory extends BasePooledObjectFactory<NettyClient> { private String ip; private int port; public NettyClientFactory(String ip, int port) { this.ip = ip; this.port = port; } @Override public NettyClient create() throws Exception { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(new NioEventLoopGroup()); bootstrap.channel(NioSocketChannel.class); bootstrap.option(ChannelOption.SO_KEEPALIVE, true); //设置重连机制 bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline().addLast(new NettyClientHandler()); channel.pipeline().addLast(new IdleStateHandler(0, 5, 0, TimeUnit.SECONDS)); } }); ChannelFuture channelFuture = bootstrap.connect(ip, port); channelFuture.awaitUninterruptibly(); if (channelFuture != null && channelFuture.isSuccess()) { return new NettyClient(channelFuture.channel()); } return null; } @Override public PooledObject<NettyClient> wrap(NettyClient nettyClient) { return new DefaultPooledObject<>(nettyClient); } }
三、Netty4源码
深入探究Netty4源码可以大幅度提高我们对Netty4的理解和认识,方便我们更好的使用和维护Netty4。
Netty4的主要源码结构如下:
+- common -- 通用的代码 +- buffer -- 字节缓存相关的代码,包括ByteBuf的实现、池化等 +- codec -- 编码和解码相关的代码 +- channel -- 整体框架代码,包括Channel和EventLoop的实现 +- handler -- 处理器相关的代码 +- transport -- 传输相关的代码,包括网络传输和本地传输 +- resolver -- 解析器相关的代码 +- resolver-dns -- DNS解析器相关的代码
其中,参考使用ChannelInboundHandlerAdapter实现简单的数据读取处理,如下代码所示:
public class NettyServerHandler extends ChannelInboundHandlerAdapter { private static final Logger log = LoggerFactory.getLogger(NettyServerHandler.class); @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] data = new byte[buf.readableBytes()]; buf.readBytes(data); String request = new String(data, "UTF-8"); log.info("Server received message: {}", request); ByteBuf resp = Unpooled.copiedBuffer("Hello, I'm server!", CharsetUtil.UTF_8); ctx.write(resp); ctx.flush(); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { log.error("Exception caught: {}", cause.getMessage()); ctx.close(); } }
四、Netty4 TCP开发
使用Netty的TCP开发,可以让我们非常轻松、高效、安全地实现TCP协议方面的开发工作。
下面是一个基于Netty4实现的TCP客户端代码示例:
public class NettyTcpClient { static final String HOST = System.getProperty("host", "127.0.0.1"); static final int PORT = Integer.parseInt(System.getProperty("port", "8080")); public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(1); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new NettyClientHandler()); } }); ChannelFuture f = b.connect(HOST, PORT).sync(); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } }
五、Netty4核心原理
从底层分析Netty4的核心原理可以更好地帮助我们理解和使用Netty4。
Netty4的核心原理是基于NIO的异步网络通信,NIO通过Selector机制在一组Channel中逐个轮询事件,只有一个线程能够轮询并处理多个Channel,因此Netty4是通过NioEventLoop来负责I/O处理事件。
下面是NioEventLoop的源码片段:
public void run() { while (!Thread.interrupted()) { try { // 通过selector来取到Channel int numReady = selectStrategy.calculateStrategy(selectNowSupplier, hasTasks()); // ... // 通过selector方式来获取I/O事件 processSelectedKeys(); // 处理Channel上的所有I/O任务和定时任务 runAllTasks(); // ... } catch (Throwable t) { // ... } } // ... }
六、Netty4和5有什么区别
Netty5相比于Netty4在某些方面进行了较大的改变,比如在编解码器方面进行不同程度的优化、异步API使用更加灵活等。
下面是Netty4和Netty5对比的一些区别:
1、Netty4采用EventLoop和EventExecutor分离的设计思路,而Netty5采用异步的ActiveObject计算模型; 2、Netty5新增了一些基于HTTP/2协议的组件; 3、Netty5提供了更加灵活的异步API机制,可以更精细地控制异步事件的执行逻辑; 4、Netty5的通信协议栈进行了重新设计,比如在编解码器方面进行了不同程度的优化; 5、Netty5底层的异步事件处理引擎也进行了改进,更加适配不同场景的使用;
结语
Netty4是一个功能强大、易于使用、高性能的异步网络编程框架,它提供了丰富的网络协议支持和超高的吞吐量,是目前业界最为流行的异步网络编程框架之一。通过对Netty4的全方位解析,更加深入地理解Netty4的使用、原理和优势。