Netty 入门指南

文章目录

  • 前言
  • Netty介绍
  • Netty发展历程
  • Netty核心组件
  • 实现HTTP服务器
  • 总结

前言

上文《BIO、NIO、IO多路复用模型详细介绍&Java NIO 网络编程》介绍了几种IO模型以及Java NIO,了解了在网络编程时使用哪种模型可以提高系统性能及效率。即使Java NIO可以帮助开发人员编写和维护网络应用程序,但由于其复杂性以及bug问题,还是诞生很多强大和流行的网络编程框架,比如Netty、Undertow、Grizzly,在平时的开发中大家更倾向于选择这些框架进行开发,而在我们学习和理解网络编程的底层原理时,使用Java NIO可以更加直接和深入地了解底层操作。本文对 Netty 进行简单介绍,并通过 Netty 实现一个HTTP服务器。

Netty介绍

Netty是一个基于Java的高性能网络应用框架,它封装了Java NIO的复杂性,提供了简单而强大的网络编程API,使得开发者能够更方便地构建高性能、可伸缩的网络应用程序。所以说学习Netty前先理解一下Java NIO是很有必要的,不然云里雾里的。

使用Netty能有多强大呢?包括但不限于以下几点:

  1. 高性能的IO处理:如果基于Java NIO开发一个成熟的应用,要非常注意如ByteBuffer内存泄漏、Channel注册连接、线程管理等问题。而Netty能够更好地处理连接管理、线程模型和内存管理等方面的问题,从而提供更高的吞吐量和更低的延迟。
  2. 强大的功能扩展:如果基于Java NIO写一个HTTP协议、Websocket协议,那我们需要考虑格式、编解码问题,而Netty提供提供了丰富的扩展点,比如编解码器、处理器和拦截器等,开发人员可以通过不同的配置搭建HTTP、WebSocket、TCP和UDP等协议,也可以轻松地添加编解码器,实现自定义协议。
  3. 可靠性和稳定性:Netty具有良好的容错能力和稳定性,能够处理各种网络故障和异常情况,并提供了多种容错和恢复机制,如断线重连和心跳机制等。

总的来说,在开发网络应用程序时使用Netty能够更专注于业务逻辑。下图为Netty所支持的功能
在这里插入图片描述

Netty发展历程

为了进一步了解Netty,这里介绍一下Netty的前世今生。

  • 2004年:Netty的前身Jboss Netty项目在JBoss公司内部启动,目标是提供一个可扩展的、易用的网络编程框架。
  • 2008年:Netty项目在JBoss公司内部开源,并发布了第一个公开版本Netty 3.0。该版本主要针对TCP和HTTP协议进行了支持。
  • 2011年:Netty 3.2发布,引入了更多的特性和改进,包括更好的性能和更灵活的API设计。
  • 2012年:Netty 4.0发布,这是一个重大的里程碑版本。在这个版本中,Netty进行了全面的重构和优化,引入了新的API设计和更高级的特性。
  • 2013年:Netty 4.0获得了广泛的认可和采用,并成为了许多大型互联网公司和项目的首选网络编程框架。同年底发布了5.0.0.Alpha1,目标是对Netty 4改进和优化。
  • 2015年:Netty 5在开发过程中遇到了一些挑战和技术难题,决定暂停Netty 5的开发,并将重心转移到Netty 4的改进和维护上。
  • 2016年:Netty 4.1发布,基于4.0版本进一步改进和优化,提供了更好的性能和更多的功能。

目前有很多知名的项目都选用了Netty作为网络通信的基础,比如知名的RPC框架Dubbo、gRPC,消息队列Kafka、RocketMQ,搜索引擎Elasticsearch等,所以当学习了解这些项目时,Netty会作为一个加分项。

Netty核心组件

因为Netty是基于Java NIO封装的,更加的抽象,要使用Netty进行开发,必须要熟悉Netty中的几个核心组件,下面一一介绍:

  1. Channel(通道):与Java NIO中的SocketChannel一样,可以进行数据的读取和写入。
  2. EventLoop(事件循环):EventLoop是Netty的事件处理机制,它负责处理各种事件,包括连接的建立与关闭、数据的读取与写入等。可以理解成Java NIO中的Selector监听socket得事件,只不过Netty时多线程处理,后面代码中有体现。
  3. ChannelHandler(通道处理器):用来处理Channel中的事件和数据的组件,例如对数据编解码、业务逻辑处理等。Netty提供了许多内置的ChannelHandler,用于处理网络连接和I/O操作。以下是一些常用的ChannelHandler:
    • ChannelInboundHandler:用于处理入站事件,例如连接建立、数据读取等。
    • ChannelOutboundHandler:用于处理出站事件,例如数据写入、连接关闭等。
    • SimpleChannelInboundHandler:继承自ChannelInboundHandler,简化了消息处理的逻辑。
    • SimpleChannelOutboundHandler:继承自ChannelOutboundHandler,简化了消息发送的逻辑。
    • HttpServerCodec:它负责处理 HTTP 请求和响应的编解码。
    • HttpObjectAggregator:将 HTTP 请求的多个部分合并成一个完整的 FullHttpRequest。
    • WebSocketServerProtocolHandler:处理 WebSocket 协议的握手和帧的编解码。
  4. ChannelPipeline(通道管道):ChannelPipeline是一个事件处理器链,用于管理和执行ChannelHandler,每个Channel都有一个对应的Pipeline,当数据进入或离开Channel时,会经过Pipeline中的一系列ChannelHandler进行处理。
  5. ByteBuf(字节缓冲区):ByteBuf是Netty中的字节容器,用于高效地存储和传输字节数据。与Java NIO的ByteBuffer相比,ByteBuf提供了更灵活的API和更高效的内存管理。
  6. Future(异步操作结果):Netty中的操作都是异步的,Future用来获取操作的状态和结果。
  7. Bootstrap(引导类):Bootstrap是启动客户端的类,负责配置和启动客户端的相关组件。
  8. ServerBootstrap(服务器引导类):ServerBootstrap是创建和启动服务器的类,用于配置和管理服务器的各个组件。

实现HTTP服务器

下面以HTTP协议为例,用Netty编写一个HTTP服务器。在这之前,我们先用上篇文章的NIOServer接收一下浏览器的请求,大概是这样的:

GET / HTTP/1.1
Host: localhost:8888
Connection: keep-alive
sec-ch-ua: "Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

可以看到接收到了一个HTTP请求的报文数据,有请求行、请求头和请求主体,这时候也能看到浏览器返回的响应是:ERR_INVALID_HTTP_RESPONSE,发送的响应无效。为什么?这是因为NIOServer中的输出格式HTTP协议不认识。
所以如果使用Java NIO实现一个HTTP服务器,需要处理很多的工作,但是如果用Netty实现一个HTTP服务器非常简单,直接上代码:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.CharsetUtil;import java.util.List;
import java.util.Map;public class HttpServer {private final int port;public HttpServer(int port) {this.port = port;}public void start() throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();//将原始的HTTP请求和响应数据进行编解码p.addLast(new HttpServerCodec());//将HTTP请求或响应的多个部分合并成一个完整的消息p.addLast(new HttpObjectAggregator(65536));p.addLast(new SimpleChannelInboundHandler<FullHttpRequest>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {//查询URI中的参数:QueryStringDecoder decoder = new QueryStringDecoder(request.uri());Map<String, List<String>> params = decoder.parameters();System.out.println(params);ByteBuf content = request.content();//请求主体中的参数String requestBody = content.toString(CharsetUtil.UTF_8);System.out.println(requestBody);String responseContent = "你好, Netty!";FullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseContent.getBytes()));response.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_HTML + ";charset=utf-8");response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);}});}});ChannelFuture f = b.bind(port).sync();f.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 8080;HttpServer server = new HttpServer(port);System.out.println("Server started on port " + port);server.start();}
}

运行这个示例后,你可以使用浏览器或者其他工具发送HTTP请求到 http://localhost:8080 ,一个HTTP服务器就诞生了,非常简单。接下来对代码进行讲解:

代码中的b.group(bossGroup, workerGroup)意思是有两个线程组会去处理服务器中的IO事件,bossGroup只用一个线程来专门负责监听服务端的端口,接收客户端连接请求,并将连接分配给 workerGroup 中的 EventLoop 进行处理;workerGroup负责处理已接收的连接的 I/O 事件,将请求解码、处理业务逻辑以及发送响应等操作都交给 EventLoop 来处理。这个是典型的主从Reactor模式,通过将连接的接收和处理分离到不同的线程池中,可以提高网络应用程序的性能,模型如下。
在这里插入图片描述

NioServerSocketChannel是指定服务器的Channel类型,还有NioDatagramChannel等类型,取决于应用场景。

.handler(new LoggingHandler(LogLevel.INFO))是为bossGroup指定一个通道处理器,记录进出 Channel 的数据流,将相关信息打印到日志中,便于排查。

.childHandler()则是为workerGroup中的EventLoop配置处理器,比如请求解码、处理业务逻辑以及发送响应。ChannelPipeline就是添加具体的通道处理器,代码中的HttpServerCodecHttpObjectAggregator处理器都是用来处理HTTP请求的编解码,SimpleChannelInboundHandler则是拿到经过多个处理器的数据流后进行业务逻辑及响应。

总结

Netty是一个非常优秀的、强大的、高性能的网络通信框架,在这个互联网飞速发展的时代,我们需要了解并且使用像这样的优秀的框架,帮助我们快速开发应用,在使用它的同时要知其原理,也可以在业务中进行创新,就像Dubbo、gRPC、Zookeeper一样采用Netty成为与其一样优秀的框架。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/28093.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

44.实现爱尔兰B公式计算并输出表格(matlab程序)

1.简述 1.话务量定义 话务量指在一特定时间内呼叫次数与每次呼叫平均占用时间的乘积。 话务量反映了电话负荷的大小&#xff0c;与呼叫强度和呼叫保持时间有关。呼叫强度是单位时间内发生的呼叫次数&#xff0c;呼叫保持时间也就是占用时间。 话务量计算方法 话务量公式为…

低功耗LoRaWAN国产低功耗LoRa+RF射频前端芯片XD6500S

目录 典型应用XD6500S简介芯片特性 LoRa系列选型参考 LoRa是为低数据速率、远距离距离和超低功耗而优化的扩频协议&#xff0c;用于LPWAN应用程序的通信。 典型应用 一、智慧农业   智慧农业大田解决方案利用传感设备、自动化控制设备、气象站实时监测采集田间土壤墒情、气象…

HTTP协议——应用层

HTTP协议 只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解析, 就是ok的. 这种约定, 就是 应用层协议 HTTP简介 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;协议又叫做超文本传输协议&#xff0c;是一个简单的请求-响应协议&#xff0c;HTTP通常运行…

MyBatis简介及环境配置

文章目录 一、什么是MyBatis二、MyBatis开发环境配置1.创建数据库表2.添加MyBatis框架支持3.配置连接字符串和MyBatis4.添加业务代码流程 一、什么是MyBatis MyBatis是一种持久层框架&#xff0c;也是一种ORM框架&#xff08;Object Relational Mapping即对象关系映射&#xf…

【AutoLayout案例1-按钮居中显示 Objective-C语言】

一、按钮居中显示 1.接下来,我们就用这个autoLayout,自动布局,给大家写一个,实现几个案例,给大家看一下 那么,首先,第一个,大家注意, 当我们使用autoLayout,自动布局的时候,我们新建一个项目, 这个新建的项目,里面有一个控制器,这个控制器,是不是默认,是四四…

基于短信宝API零代码实现短信自动化业务

场景描述&#xff1a; 基于短信宝开放的API能力&#xff0c;实现在特定事件&#xff08;如天气预警&#xff09;或定时自动发送短信&#xff08;本文以定时群发短信为例&#xff09;。通过Aboter平台如何实现呢&#xff1f; 使用方法&#xff1a; 首先创建一个IPaaS流程&…

iPhone苹果手机地震预警功能怎么开启?

iPhone苹果手机地震预警功能怎么开启&#xff1f; 1、打开iPhone苹果手机设置&#xff1b; 2、在iPhone苹果手机设置内找到辅助功能&#xff1b; 3、在辅助功能内找到触控&#xff1b; 4、在iPhone苹果手机辅助功能触控内找到振动&#xff0c;如果是关闭状态请启&#xff1b; …

C++ STL vector

目录 一.认识vector 二.vector的使用 1.vector的构造函数 2.vector的迭代器 2.1 begin&#xff08;&#xff09;&#xff0c;end&#xff08;&#xff09; 2.2 rbegin&#xff08;&#xff09;&#xff0c;rend&#xff08;&#xff09; 2.3 迭代器初始化对象 3. vector…

Linux中安装Tomcat

Linux安装Tomcat 操作步骤: 1、使用FinalShell自带的上传工具将Tomcat的二进制发布包上传到Linux 2、解压安装包&#xff0c;命令为tar -zxvf apache-tomcat-7.0.57.tar.gz -C /usr/local 3、进入Tomcat的bin目录启动服务&#xff0c;命令为sh startup.sh或者./ startup.sh …

leetcode每日一练-第278题-第一个错误的版本

一、思路 二分查找——因为它可以快速地将版本范围缩小一半&#xff0c;从而更快地找到第一个坏版本。 二、解题方法 维护一个左边界 left 和一个右边界 right&#xff0c;在每一步循环中&#xff0c;我们计算中间版本 mid&#xff0c;然后检查它是否是坏版本。如果是坏版本…

利用Overleaf使用Latex插入算法伪代码

目录 一个简单的例子&#xff1a; 样式一&#xff08;algorithm2e算法&#xff09;&#xff1a; 样例二&#xff08;algorithm2e算法&#xff09;&#xff1a; 样式三&#xff08;algorithm算法&#xff09;&#xff1a; 下面详细讲解algorithm2e算法的使用 1、宏包参数的…

2023华数杯数学建模C题完整5问代码思路分析

目前已经写出2023华数杯C题母亲身心健康对婴儿成长的影响全部5问的完整代码和42页论文&#xff08;正文30页&#xff0c;论文部分摘要如下&#xff1a; 本文共解决了五个问题&#xff0c;涉及婴儿行为特征、睡眠质量与母亲的身体指标和心理指标的关系&#xff0c;以及如何优化…

使用Socket实现TCP版的回显服务器

文章目录 1. Socket简介2. ServerSocket3. Socket4. 服务器端代码5. 客户端代码 1. Socket简介 Socket&#xff08;Java套接字&#xff09;是Java编程语言提供的一组类和接口&#xff0c;用于实现网络通信。它基于Socket编程接口&#xff0c;提供了一种简单而强大的方式来实现…

【MATLAB第66期】#源码分享 | 基于MATLAB的PAWN全局敏感性分析模型(有条件参数和无条件参数)

【MATLAB第66期】#源码分享 | 基于MATLAB的PAWN全局敏感性分析模型&#xff08;有条件参数和无条件参数&#xff09; 文献参考 Pianosi, F., Wagener, T., 2015. A simple and efficient method for global sensitivity analysis based on cumulative distribution functions.…

zuul实现黑名单,request多次读取问题,stream close

一&#xff0c;背景及设计 1.需要在网关实现黑名单功能&#xff0c;实现拦截指定接口。黑名单用户&#xff0c;会加入指定黑名单列表&#xff0c;关联对应功能&#xff0c;如用户登录&#xff0c;用户下单&#xff0c;用户接单。 2.表设计 平台表&#xff1a;不同系统 黑名单…

Grafana 曲线图报错“parse_exception: Encountered...”

问题现象 配置的Grafana图报错如下&#xff1a; 原因分析 点开报错&#xff0c;可以看到报错详细信息&#xff0c;是查询语句的语法出现了异常。 变量pool的取值为None 解决方案 需要修改变量pool的查询SQL&#xff0c;修改效果如下&#xff1a; 修改后&#x…

HTML5注册页面

分析 注册界面实际上是一个表格&#xff08;对齐&#xff09;&#xff0c;一行有两个单元格。 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevic…

行业追踪,2023-08-08

自动复盘 2023-08-08 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

Vue2 第二十节 vue-router (四)

1.全局前置路由和后置路由 2.独享路由守卫 3.组件内路由守卫 4.路由器的两种工作模式 路由 作用&#xff1a;对路由进行权限控制 分类&#xff1a;全局守卫&#xff0c;独享守卫&#xff0c;组件内守卫 一.全局前置路由和后置路由 ① 前置路由守卫&#xff1a;每次路由…

设计模式之策略模式(Strategy)

一、概述 定义一系列的算法&#xff0c;把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的类而变化。 二、适用性 1.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。 2.需要使用一个算法的不同变体。…