Netty实战(十一)
预置的ChannelHandler和编解码器(一)HTTP和SSL/TLS的添加和使用
- 一、SSL和TLS添加
- 二、基于Netty的HTTP程序
- 2.1 HTTP解码器、编码器和编解码器
- 2.2 聚合HTTP消息
- 2.3 HTTP压缩
一、SSL和TLS添加
作为一个通讯框架,通讯数据的安全性也是不可或缺的一部分。一般常见的像TLS/SSL这样的安全协议我们都应该熟悉。 我们在访问安全网站时都遇到过这些协议,但是它们也可用于其他不是基于HTTP的应用程序,如安全SMTP(SMTPS)邮件服务器甚至是关系型数据库系统。
像Java就提供了javax.net.ssl 包来支持SSL/TLS,它的 SSLContext 和 SSLEngine类使得实现解密和加密相当简单直接。Netty 则是通过一个名为 SslHandler 的 ChannelHandler实现利用了这个 API,其中 SslHandler 在内部使用 SSLEngine 来完成实际的工作。
Netty 的 OpenSSL/SSLEngine 实现:
Netty 还提供了使用 OpenSSL工具包(www.openssl.org)的 SSLEngine 实现。这个 OpenSslEngine 类提供了比 JDK 提供的SSLEngine 实现更好的性能。如果OpenSSL库可用,可以将Netty应用程序(客户端和服务器)配置为默认使用OpenSslEngine。 如果不可用,Netty将会回退到 JDK 实现。 注意,无论你使用 JDK 的 SSLEngine 还是使用 Netty 的 OpenSslEngine,SSL API 和数据流都 是一致的。
下面这张图展示了SslHandler 进行解密和加密数据流:
下面我们使用ChannelInitializer来将SslHandler添加到ChannelPipeline 中,ChannelInitializer在channel注册好时设置ChannelPipeline 我们之前说过,忘记可以看看前面的内容。
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;import javax.net.ssl.SSLEngine;/*** Author: lhd* Data: 2023/6/11* Annotate: Netty 添加SSL/TLS支持*/
public class SslChannelInitializer extends ChannelInitializer<Channel> {private final SslContext context;private final boolean startTls;//传入要使用的SslContext,startTls如果设置为 true,第一个写入的消息将不会被加密(客户端应该设置为 true)public SslChannelInitializer(SslContext context, boolean startTls) {this.context = context;this.startTls = startTls;}@Overrideprotected void initChannel(Channel ch) throws Exception {//对于每个 SslHandler 实例,都使用 Channel 的 ByteBufAllocator 从 SslContext 获取一个新的 SSLEngineSSLEngine engine = context.newEngine(ch.alloc());//将 SslHandler 作为第一个ChannelHandler 添加到 ChannelPipeline 中ch.pipeline().addFirst("ssl", new SslHandler(engine, startTls));}
}
SslHandler同样包含其他的方法,例如:在握手阶段,两个节点将相互验证并且商定一种加密方式。我们可以配置 SslHandler 来修改它的行为,或者在 SSL/TLS握手一旦完成之后提供通知,握手阶段完成之后,所有的数据都将会被加密。SSL/TLS 握手将会被自动执行。
下面是一些SslHandler的方法:
方 法 名 称 | 描 述 |
---|---|
setHandshakeTimeout (long,TimeUnit);setHandshakeTimeoutMillis (long);getHandshakeTimeoutMillis() | 设置和获取超时时间,超时之后,握手ChannelFuture 将会被通知失败 |
setCloseNotifyTimeout (long,TimeUnit);setCloseNotifyTimeoutMillis (long);getCloseNotifyTimeoutMillis() | 设置和获取超时时间,超时之后,将会触发一个关闭通知并关闭连接。这也将会导致通知该 ChannelFuture 失败 |
handshakeFuture() | 返回一个在握手完成后将会得到通知的ChannelFuture。如果握手先前已经执行过了,则返回一个包含了先前的握手结果的 ChannelFuture |
close();close(ChannelPromise);close(ChannelHandlerContext,ChannelPromise) | 发送 close_notify 以请求关闭并销毁 |
底层的 SslEngine |
二、基于Netty的HTTP程序
HTTP/HTTPS大部分同学都不会陌生,它是我们常用的协议之一。我们熟悉的另一个协议 WebService API 一般也是基于HTTP/HTTPS的。
下面我们使用Netty 提供的 ChannelHandler,来处理 HTTP 和 HTTPS协议。
2.1 HTTP解码器、编码器和编解码器
HTTP 是基于请求/响应模式的:客户端向服务器发送一个 HTTP 请求,然后服务器将会返回一个 HTTP 响应。Netty 提供了多种编码器和解码器简化了对这个协议的使用。
我们先来看看如生产和消费HTTP请求以及HTTP响应的方法:
- 下图是一个HTTP的请求的组成:
- 下图是HTTP响应的组成:
一个 HTTP 请求/响应可能由多个数据部分组成,并且它总是以一个 LastHttpContent部分作为结束。FullHttpRequest 和 FullHttpResponse 消息是特殊的子类型,分别代表了完整的请求和响应。所有类型的 HTTP 消息都实现了 HttpObject 接口。
那么HTTP的编码器和解码器都包含哪些方法呢?
名 称 | 描 述 |
---|---|
HttpRequestEncoder | 将HttpRequest、HttpContent 和 LastHttpContent 消息编码为字节 |
HttpResponseEncoder | 将HttpResponse、HttpContent 和LastHttpContent 消息编码为字节 |
HttpRequestDecoder | 将字节解码为HttpRequest、HttpContent 和 LastHttpContent 消息 |
HttpResponseDecoder | 将字节解码为HttpResponse、HttpContent 和LastHttpContent 消息 |
了解了HTTP协议后,我们将它添加到我们的应用程序中:
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;/*** Author: lhd* Data: 2023/6/11* Annotate: 添加HTTP协议支持*/
public class HttpPipelineInitializer extends ChannelInitializer<Channel> {private final boolean client;public HttpPipelineInitializer(boolean client) {this.client = client;}@Overrideprotected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();if (client) {//如果是客户端,则添加HttpResponseDecoder 以处理来自服务器的响应pipeline.addLast("decoder", new HttpResponseDecoder());//如果是客户端,则添加 HttpRequestEncoder以向服务器发送请求pipeline.addLast("encoder", new HttpRequestEncoder());} else {//如果是服务器,则添加 HttpResponseEncoder以向客户端发送响应pipeline.addLast("decoder", new HttpRequestDecoder());//如果是服务器,则添加 HttpRequestDecoder以接收来自客户端的请求pipeline.addLast("encoder", new HttpResponseEncoder());}}
}
2.2 聚合HTTP消息
为什么要聚合HTTP消息?
ChannelInitializer 将 ChannelHandler 安装到 ChannelPipeline中之后,便可以处理不同类型的 HttpObject 消息了。但是由于 HTTP
的请求和响应可能由许多部分组成,因此需要聚合它们以形成完整的消息。
Neey是如何做的?
Netty 提供了一个聚合器,它可以将多个消息部分合并为 FullHttpRequest 或者 FullHttpResponse 消息。通过这样的方式,我们将看到完整的消息内容。由于消息分段需要被缓冲,直到可以转发一个完整的消息给下一个 ChannelInboundHandler,所以这个操作有轻微的开销。
下面展示一下这种操作是如何进行的:
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;/*** Author: lhd* Data: 2023/6/11* Annotate: HTTP消息聚合*/
public class HttpAggregatorInitializer extends ChannelInitializer<Channel> {private final boolean isClient;public HttpAggregatorInitializer(boolean isClient) {this.isClient = isClient;}@Overrideprotected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();if (isClient) {//如果是客户端,则添加 HttpClientCodecpipeline.addLast("codec", new HttpClientCodec());} else {//如果是服务器,则添加 HttpServerCodecpipeline.addLast("codec", new HttpServerCodec());}//将最大的消息大小为 512 KB的 HttpObjectAggregator 添加到 ChannelPipelinepipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));}
}
2.3 HTTP压缩
HTTP为什么要压缩?不是已经聚合了么?
当使用 HTTP 时,压缩可以尽可能的多地减小传输数据的大小。虽然压缩会带来一些 CPU时钟周期上的开销,但是通常来说它都是一个好主意,特别是对于文本数据来说。
Netty 为压缩和解压缩提供了 ChannelHandler 实现,它们同时支持 gzip 和 deflate 编 码。
HTTP 请求的头部信息
客户端可以通过提供以下头部信息来指示服务器它所支持的压缩格式:
GET /encrypted-area HTTP/1.1
Host: www.example.com
Accept-Encoding: gzip, deflate
然而,需要注意的是,服务器没有义务压缩它所发送的数据。
下面展示一下如何自动的压缩HTTP消息:
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.codec.http.HttpServerCodec;/*** Author: lhd* Data: 2023/6/11* Annotate: HTTP消息压缩*/
public class HttpCompressionInitializer extends ChannelInitializer<Channel> {private final boolean isClient;public HttpCompressionInitializer(boolean isClient) {this.isClient = isClient;}@Overrideprotected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();if (isClient) {//如果是客户端,则添加 HttpClientCodecpipeline.addLast("codec", new HttpClientCodec());//如果是客户端,则添加HttpContentDecompressor 以处理来自服务器的压缩内容pipeline.addLast("decompressor", new HttpContentDecompressor());} else {//如果是服务器,则添加 HttpServerCodecpipeline.addLast("codec", new HttpServerCodec());//如果是服务器,则添加HttpContentCompressor来压缩数据(如果客户端支持它)pipeline.addLast("compressor", new HttpContentCompressor());}}
}
压缩及其依赖
如果你正在使用的是 JDK 6 或者更早的版本,那么你需要将 JZlib(www.jcraft.com/jzlib/)添加到CLASSPATH 中以支持压缩功能。
对于 Maven,请添加以下依赖项:
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.1.3</version>
</dependency>
相关文章:
Netty实战(十一)
预置的ChannelHandler和编解码器(一)HTTP和SSL/TLS的添加和使用 一、SSL和TLS添加二、基于Netty的HTTP程序2.1 HTTP解码器、编码器和编解码器2.2 聚合HTTP消息2.3 HTTP压缩 一、SSL和TLS添加 作为一个通讯框架,通讯数据的安全性也是不可或缺的…...
Qos服务质量、心跳机制、保留消息,遗嘱信息,用户密码认证
这里写目录标题 Qos服务质量使用ESP8266接收QoS1的MQTT消息保留消息(retainFlag)心跳机制遗嘱信息 Qos服务质量 若想实现QoS>0,订阅端连接服务端时cleanSession需要设置为false,订阅端订阅主题时QoS>0,发布端发…...
MATLAB 之 线性方程组求解
这里写目录标题 一、线性方程组求解1. 线性方程组的直接解法1.1 利用左除运算符的直接解法1.2 利用矩阵的分解求解线性方程组 2. 线性方程组的迭代解法2.1 Jacobi 迭代法2.2 Gauss-Serdel 迭代法 3. 求线性方程的通解 一、线性方程组求解 在 MATLAB 中,关于线性方程…...
华为OD机试真题 Java 实现【字符串序列判定】【2022Q4 100分】,附详细解题思路
一、题目描述 输入两个字符串a和b,都只包含英文小写字母。a长度<=100,b长度<=500,000。 判定a是否是b的有效子串。 判定规则: a中的每个字符在b中都能找到(可以不连续),且a在b中字符的前后顺序与a中顺序要保持一致。 (例如,a=”qwt”是b=”qwerty”的一个子…...
taro使用小记 —— 持续更新
目录 1、在 taro 中使用 axios2、在 taro 中添加全局组件自动引入和方法自动引入3、在 taro 中使用 pinia 1、在 taro 中使用 axios taro 3.6 版本已经支持了网络请求库。 需安装插件 tarojs/plugin-http 使用和注意事项说明: https://www.npmjs.com/package/taroj…...
【LeetCode】110. 平衡二叉树
110. 平衡二叉树(简单) 思路 对二叉树做先序遍历,从底至顶返回子树最大高度,若判定某子树不是平衡树则“剪枝”直接向上返回。 递归返回值: 当节点 root 左、右子树的高度差 > 1:返回 -1,代…...
SQL视图、存储过程、触发器
一、视图 (一)介绍 视图(view)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。 通俗的讲,视图只保存了查询的SQL逻辑&…...
DNS隧道穿透
介绍: DNS隧道,是隧道技术中的一种。当我们的HTTP、HTTPS这样的上层协议、正反向端口转发都失败的时候,可以尝试使用DNS隧道。DNS隧道很难防范,因为平时的业务也好,使用也罢,难免会用到DNS协议进行解析&am…...
1.2 Scala变量与数据类型
一、变量声明 (一)简单说明 Scala中变量的声明使用关键字val和var。val类似Java中的final变量,也就是常量,一旦初始化将不可修改;var类似Java中的非final变量,可以被多次赋值,多次修改。 val - …...
深入探讨软件测试的质量度量指标
本文的目的是介绍项目中使用到主要质量指标,这些质量指标可以分为以下三类: 质量保证过程指标生产事故管理指标度量质量文化指标 质量保证过程指标 质量保证指标可以通过测试覆盖率来度量功能和非功能测试的覆盖率,同时也可以根据测试发现…...
6.12作业
1、pinia和vuex的区别 1.pinia没有mutations,只有state,getters,actions 2.pinia分模块不需要modules (之前vuex分模块需要modules) 3.pinia体积更小(性能更好) 4.pinia可以直接修改state数据 2、Vue2和vue3的响应式原理分别是什么&#x…...
RabbitMQ集群部署之镜像模式
RabbitMQ集群的普通模式中,一旦创建队列的主机宕机,队列就会不可用。不具备高可用能力。如果要解决这个问题,必须使用官方提供的镜像集群方案。 官方文档地址:https://www.rabbitmq.com/ha.html 1.镜像模式的特征 默认情况下&a…...
【算法】Remove Zero Sum Consecutive Nodes from Linked List 从链表中删去总和值为零的连续节点
文章目录 Remove Zero Sum Consecutive Nodes from Linked List 从链表中删去总和值为零的连续节点问题描述:分析代码 Remove Zero Sum Consecutive Nodes from Linked List 从链表中删去总和值为零的连续节点 问题描述: 给你一个链表的头节点 head&am…...
音悦台项目测试报告
文章目录 项目背景项目功能测试计划与设计功能测试自动化测试 测试结果功能测试结果UI自动化测试结果 项目背景 现如今人们的生活压力大,容易使人疲惫,为了使得人们在闲暇之余可以听音乐放松,为此设计出一款轻量的听音乐网站,快速…...
数据库存储过程和函数
MySQL存储过程和存储函数 MySQL中提供存储过程(procedure)与存储函数(function)机制,我们先将其统称为存储程序,一般的SQL语句需要先编译然后执行,存储程序是一组为了完成特定功能的SQL语句集&…...
Spring依赖注入有哪些?各有什么优缺点?
文章目录 前言概述一、属性注入1.1 实例1.2 优点1.3 缺点 二、Setter注入2.1 实例2.2 优点2.3 缺点 三、 构造方法注入3.1 实例3.2 优点3.3 缺点 四、扩展 前言 IoC和DI是Spring中重要的两个概念,其中IoC指的是控制反转,DI(依赖注入)指的是IoC的具体实现…...
java八股文-并发篇
并发篇 1. 线程状态 要求 掌握 Java 线程六种状态掌握 Java 线程状态转换能理解五种状态与六种状态两种说法的区别 六种状态及转换 分别是 新建 当一个线程对象被创建,但还未调用 start 方法时处于新建状态此时未与操作系统底层线程关联 可运行 调用了 start …...
Elasticsearch8.6.0安装
Elasticsearch 8.5.0 安装 Elasticsearch 简介Elasticsearch 8.6.0 安装创建网络拉取镜像运行镜像设置密码修改kibana配置绑定ES代码绑定:手动绑定: 配置ik分词器扩展词词典停用词词典 Elasticsearch 简介 Elasticsearch(ES) 是一…...
Vue - 第五天 动态组件 插槽 自定义指令
动态组件& 插槽& 自定义指令 一、动态组件1.什么是动态组件2.如何实现动态组件渲染3.使用 keep-alive 保持状态4. keep-alive 对应的生命周期函数5. keep-alive 的 include 属性6.动态展示左右组件7.例子 二、插槽1.什么是插槽2.体验插槽的基础用法2.1 没有预留插槽的内…...
如何开展web自动化测试
Web 自动化是指使用测试脚本在 Web 上自动执行任务。它包括填写表单、导航网页、单击链接或按钮以及从网站中提取数据等任务。 它可用于各种目的,例如自动输入数据或测试网站的功能。有几种工具和编程语言可用于自动化网络上的任务,包括Selenium&#x…...
【博学谷学习记录】超强总结,用心分享 | 架构师 Maven学习总结
文章目录 Maven基本1.什么是Maven2.为什么用Maven?(1)jar 包的规模(2) jar 包的来源(3)jar 包之间的依赖关系 3.Maven目录结构4.maven仓库配置 Pom层次Pom文件简介Super POM 依赖管理1 依赖传递2 传递性依…...
PPT里文字太多如何排版-一口气教你7种布局瞬间让PPT高大上起来
简介 这是我们学PPT处于初级到中级进化阶段常做的一件事,就是拿了这种纯文字类版面来做布局。而且这种文字都是政企类的、相当苦涩难懂、无法创意。 因此我们会要求使用7种排版来优化这个版面。这和达芳奇画鸡蛋很像,这样的练习需要坚持一段时间,就是拿了纯文字来beautifu…...
Whistle(基于 Node 实现的跨平台抓包调试工具)的使用
Whistle(基于 Node 实现的跨平台抓包调试工具)的使用 基于Node实现的跨平台抓包调试工具 可以劫持网络请求,并进行请求和响应的修改,来提高我们的开发调试效率 1.一键安装(装包/证书) npm i -g whistle && w2 start --init 证书的问题 安装…...
数学模型:Python实现非线性规划
上篇文章:整数规划 文章摘要:非线性规划的Python实现。 参考书籍:数学建模算法与应用(第3版)司守奎 孙玺菁。 PS:只涉及了具体实现并不涉及底层理论。学习底层理论以及底层理论实现:可以参考1.最优化模型与算法——基于…...
Docker网路模型(四)使用 bridge 网络
使用 bridge 网络 在计算机网络中,一个 bridge(网桥)是一个链路层设备,负责在不同的网段之间转发信息。 bridge 可以是真实的硬件设备也可以是由宿主机底层提供的软件模拟设备。 在 Docker 中,bridge 网络使用了软件…...
数据结构与算法之美 | 排序(2)
归并排序(Merge Sort) 基本思想: 如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。 def merge_sort…...
【外企面试系列】必备口语短语与例句 - A系列
a big headache令人头痛的事情 I have a big headache from all the noise. (我因为噪音而头痛。)The paperwork is a big headache for me. (对我来说,文书工作是件头痛的事情。) a fraction of 一部分 She ate only a fraction of her meal. (她只吃了一部分饭…...
Java使用Opencv进行大图找小图并使用其找图功能进行bilibili视频下载案例
Java使用Opencv进行大图找小图并使用其找图功能进行bilibili视频下载案例 一、Opencv大图找小图说明二、Opencv的window安装1.下载windows下的安装包2.安装3.Java中Opencv加载测试 三、Java中通过Opencv进行模板匹配大图找小图四、进行多图查找五:案例下载bilibili视…...
肠道健康从核心菌属开始:肠道菌群的关键
谷禾健康 5月29日,是世界肠道健康日。肠道是人体最重要的消化系统之一,与人体健康紧密相关。而肠道菌群作为肠道重要组成部分,在肠道健康中发挥着重要的作用。 编辑 由于基因、环境、饮食、药物等因素的影响,每个人的肠道菌群都…...
深度学习实战37-NASNet(具有自动搜索能力的神经网络模型)的搭建与实战应用
大家好,我是微学AI,今天给大家介绍一下深度学习实战37-NASNet(具有自动搜索能力的神经网络模型)的搭建与实战应用,NASNet是由Google Brain团队开发的一种具有自动搜索能力的神经网络模型,利用强化学习和进化算法等技术来自动地搜索最优的神经网络架构。NASNet模型的设计灵感…...
昆山企业做网站/自动推广软件
###题目描述 给定n个整数的一个数组S,S中是否有元素a、b和c满足abc0?找出数组中所有满足加和为0的不同的三个数组合。 题目链接:三数之和 题目标签:数组 双指针 注意,(a,b,c)中的元素必须是非降序的排列方式(即&…...
深圳龙华汽车网站建设/太原全网推广
PHP 循环 - For 循环循环执行代码块指定的次数,或者当指定的条件为真时循环执行代码块。for 循环for 循环用于您预先知道脚本需要运行的次数的情况。语法for (初始值; 条件; 增量){ 要执行的代码;}参数:初始值:主要是初始化一个变量值&#x…...
深圳画册设计团队/网站优化排名软件推广
一般认为最好的做法是尽可能使用外部文件来包含Javascript代码。 支持使用外部文件的人多会强调如下优点: ■ 可维护性:遍及不同HTML页面的Javascript会造成维护问题。 ■ 可缓存: 浏览器能够根据具体的设置缓存链接的所有外部Javascript文件。也就是说&…...
外贸网站seo教程/河南企业网站建设
Instr()函数 InStr()函数返回一个字符串第一次出现在一个字符串,从左到右搜索。返回搜索到的字符索引位置。 语法 InStr([start,]string1,string2[,compare]) 参数说明 Start - 一个可选参数。指定搜索的起始位置。搜索从第一个位置开始,从左到右。Strin…...
wordpress 分类名/苏州seo免费咨询
rendered :注解。注释是否可以编辑 如下,注释不可编辑。我的idea打开类文件后注释都是这个状态,看着不舒服,如何取消呢 打开File - Settings - Editor - General - Appearance 把 Render documentation comments 取消勾选&#x…...
网站建设 慕课/短视频营销推广策略
编码一个SMS一般需要如下的信息:TP_Data_Coding_SchemeTP_UD编码方式TP_Destination_Address对方号码TP_Message_Reference参考号码TP_Status_Report_Request状态报告TP_User_Data用户信息TP_Validity_Priod有效期ServiceCenterNumber短信中心号码所以在编码器中存在…...