【分布式技术专题】「探索高性能远程通信」基于Netty的分布式通信框架实现(附通信协议和代码)(上)

基于Netty的分布式通信框架实现

  • 前提介绍
    • 回顾Dubbo
    • 分布式通信框架
      • 组成元素
      • 程序执行流程
      • 消息协议设计
      • 实现机制
          • ChannelInboundHandlerAdapter
            • 自定义事件处理
          • ChannelOutboundHandlerAdapter
      • 编(解)码处理器
        • 编码过程阶段
          • ChannelOutboundHandlerAdapter序列化实现
          • ChannelOutboundHandlerAdapter压缩实现
          • LengthBasedEncoder编码器
        • 解码过程阶段
      • 处理器链的建立
        • 创建`ChannelPipeline`对象
        • `ChannelPipeline`中添加处理器
        • 添加的顺序形成处理器链
    • 未完待续

前提介绍

今天,我要向大家实现一个基于Netty实现的高性能远程通信框架!这个框架利用了 Netty 的强大功能,提供了快速、可靠的远程通信能力。

无论是构建大规模微服务架构还是实现分布式计算,这个分布式通信框架都是一个不可或缺的利器。

回顾Dubbo

相信大家都指导Dubbo(Dubbo3)这个非常著名的RPC框架对吧,如果你忘记了,那么我给您先垫垫底,可以看到下面就是Dubbo的借本架构图,当然Dubbo3会更加复杂,我们先按照基础的Dubbo架构进行回顾
在这里插入图片描述
无论是在分布式系统、微服务架构还是其他需要跨网络进行通信的场景下,这个框架都能够帮助你实现高效的数据传输和通信。它具备出色的性能和可扩展性,能够满足各种复杂的通信需求。
在这里插入图片描述
但是无论是从层次化和结构化而言,Dubbo/Dubbo3都过于的复杂了,我们起始未必会用到那么复杂以及扩展性那么强的功能,因此我们来实现一个属于我们自己的一个可靠且高性能的远程通信解决方案。

分布式通信框架

分布式通信框架是一种卓越的高性能远程通信解决方案,它基于 Netty 实现了 TCP 通信的底层细节,并对上层进行了封装,以提供简单易用和高度可扩展的能力。在这里插入图片描述
这个框架能够帮助开发者轻松构建分布式系统,并实现可靠的跨网络通信。通过利用 Netty 的强大功能,该框架能够提供出色的性能和可靠性,同时还具备灵活的扩展性,可以满足各种复杂的通信需求。

组成元素

先介绍一下网络通信的两个最基本的元素和属性,如下所示。
在这里插入图片描述

  • Channel:可以理解为一个通道,即一条连接线路的概念。它承载着数据、信息或者信号的传输功能。

  • ChannelGroup:由多个通道组合而成的一个概念。它将多条通道有机地集合在一起,形成一个整体,以便更高效地进行数据、信息或者信号的传输。

程序执行流程

下图自上而下分别为boss接受连接、channel、dispatcher、event listener和service。
在这里插入图片描述
这五个部分各自承载着独特的任务,又彼此协作,形成了一个系统化、高效化的运行流程。
在这里插入图片描述

  • Boss线程:接受连接流程,主要负责接受外部请求,这些请求可能是来自用户的操作或是其他服务的调用。一旦接收到请求,boss会进行必要的处理,然后将请求分发给下面的线程池worker进行处理。

  • Worker线程:系统中的工作执行者,负责接收boss分发的任务,然后执行具体的业务逻辑。这些任务可能涉及到数据的处理、服务的调用等。线程池worker通过channel与boss进行通信,确保任务能够准确无误地传递。

  • dispatcher机制:在worker执行任务的过程中,需要有一个机制来调度和分配任务。这就是dispatcher的作用。

dispatcher根据一定的策略和规则,将任务分配给合适的worker线程进行处理。这一环节保证了系统的负载均衡和高效运行。

  • EventListener:基于在每个worker线程内部,eventListener发挥着关键作用。它负责监听和处理线程中的事件,比如任务的完成、异常等。通过eventListener,系统能够及时响应各种事件,进行必要的处理和反馈。

  • Service业务逻辑实现:它代表了整个系统的核心业务逻辑。service接收并处理来自worker线程的任务,完成具体的业务操作。这些操作可能涉及到数据的处理、服务的调用等。

消息协议设计

消息协议这里是指对消息编码和解码的规范的一种定义,通信内置的消息协议采用如下结构:其中包含了三个部分:ID、Length 和 Content。
在这里插入图片描述

  1. ID:

    • 长度:1 字节
    • 用途:表示 Content 部分是否被压缩,其中 1 表示 Content 部分被压缩,0 表示未被压缩。
  2. Length:

    • 长度:4 字节
    • 用途:表示 ID 和 Content 的总长度。这通常用于消息分片或分批传输,确保接收方可以正确地重新组装消息。
  3. Content:

    • 长度:不定(由 Length 字段决定)
    • 用途:真实的消息内容。根据 ID 的值,它可能是压缩的或未压缩的。

如果 ID 为 1,则 Content 部分可能会被某种算法(如gzip)压缩,以减少存储或传输的空间需求。Length 字段确保了数据的完整性,因为接收方可以根据这个长度字段正确地读取和重组数据。

在实际应用中,这种结构通常用于网络通信、文件存储或数据库存储等场景,其中需要对数据进行有效且紧凑的表示。

实现机制

Netty框架原生提供了一个处理器链,该链用于对事件进行处理。每个处理器都实现了 ChannelHandler 接口。ChannelHandler 接口是一个空接口,其中:ChannelInboundHandlerAdapterChannelOutboundHandlerAdapter
在这里插入图片描述
我们主要关注这两个接口,因为它们被用于处理读取输入和写入输出的消息。

ChannelInboundHandlerAdapter

ChannelInboundHandlerAdapterNetty框架中用于处理从网络到应用程序的事件的组件。它是一种特殊的ChannelHandler,主要负责处理读取操作。
在这里插入图片描述

当网络通道接收到数据时,ChannelInboundHandlerAdapter会被触发,然后开发者可以通过重写其中的方法来执行需要的操作。常见的操作包括数据的解码、解压或反序列化等。

自定义事件处理

ChannelInboundHandlerAdapterNetty中实现业务逻辑的关键组件,它提供了丰富的方法来处理不同的事件,例如通道激活、数据读取和异常处理等,下面是对应的源码:

public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {/*** Calls {@link ChannelHandlerContext#fireChannelRegistered()} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void channelRegistered(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelRegistered();}/*** Calls {@link ChannelHandlerContext#fireChannelUnregistered()} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void channelUnregistered(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelUnregistered();}/*** Calls {@link ChannelHandlerContext#fireChannelActive()} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelActive();}/*** Calls {@link ChannelHandlerContext#fireChannelInactive()} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelInactive();}/*** Calls {@link ChannelHandlerContext#fireChannelRead(Object)} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ctx.fireChannelRead(msg);}/*** Calls {@link ChannelHandlerContext#fireChannelReadComplete()} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelReadComplete();}/*** Calls {@link ChannelHandlerContext#fireUserEventTriggered(Object)} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {ctx.fireUserEventTriggered(evt);}/*** Calls {@link ChannelHandlerContext#fireChannelWritabilityChanged()} to forward* to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {ctx.fireChannelWritabilityChanged();}/*** Calls {@link ChannelHandlerContext#fireExceptionCaught(Throwable)} to forward* to the next {@link ChannelHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Override@SuppressWarnings("deprecation")public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {ctx.fireExceptionCaught(cause);}
}

通过自定义ChannelInboundHandlerAdapter,开发者可以灵活地处理从网络到应用程序的数据传输过程,稍后回进行分析介绍。

ChannelOutboundHandlerAdapter

ChannelOutboundHandlerAdapter也是一种特殊的ChannelHandler,用于处理从应用程序到网络的事件,主要包括写出操作。它是Netty框架中的一个关键组件,负责将应用程序的数据写入网络通道中,以便发送给对应的接收端。
在这里插入图片描述
使用ChannelOutboundHandlerAdapter可以实现对写出事件的定制化处理,例如数据的编码、压缩或序列化等操作,以满足具体业务需求。它可以直接扩展ChannelOutboundHandlerAdapter类,并重写其中的方法来实现特定的功能。

package io.netty.channel;
import io.netty.channel.ChannelHandlerMask.Skip;
import java.net.SocketAddress;
/*** Skeleton implementation of a {@link ChannelOutboundHandler}. This implementation just forwards each method call via* the {@link ChannelHandlerContext}.*/
public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {/*** Calls {@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void bind(ChannelHandlerContext ctx, SocketAddress localAddress,ChannelPromise promise) throws Exception {ctx.bind(localAddress, promise);}/*** Calls {@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,SocketAddress localAddress, ChannelPromise promise) throws Exception {ctx.connect(remoteAddress, localAddress, promise);}/*** Calls {@link ChannelHandlerContext#disconnect(ChannelPromise)} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void disconnect(ChannelHandlerContext ctx, ChannelPromise promise)throws Exception {ctx.disconnect(promise);}/*** Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void close(ChannelHandlerContext ctx, ChannelPromise promise)throws Exception {ctx.close(promise);}/*** Calls {@link ChannelHandlerContext#deregister(ChannelPromise)} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {ctx.deregister(promise);}/*** Calls {@link ChannelHandlerContext#read()} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void read(ChannelHandlerContext ctx) throws Exception {ctx.read();}/*** Calls {@link ChannelHandlerContext#write(Object, ChannelPromise)} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {ctx.write(msg, promise);}/*** Calls {@link ChannelHandlerContext#flush()} to forward* to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.** Sub-classes may override this method to change behavior.*/@Skip@Overridepublic void flush(ChannelHandlerContext ctx) throws Exception {ctx.flush();}
}

编(解)码处理器

编码(解码)处理器、压缩(解压)处理器以及序列化(反序列化)处理器等都是直接或间接用于实现ChannelHandler的组件。

编码过程阶段

编码过程由三个Handler组合完成,分别为序列化,压缩数据以及编码处理。
在这里插入图片描述

ChannelOutboundHandlerAdapter序列化实现

当你需要实现序列化数据的发送时,可以基于ChannelOutboundHandlerAdapter接口进行实现。下面是一个简单的示例代码,展示了如何使用write方法将序列化后的数据发送到网络:

public class SerializationHandler extends ChannelOutboundHandlerAdapter {@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {// 进行数据序列化操作,这里假设使用Java内置的序列化方式ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(msg);oos.flush();byte[] serializedData = bos.toByteArray();// 将序列化后的数据写入网络通道ByteBuf byteBuf = ctx.alloc().buffer();byteBuf.writeBytes(serializedData);ctx.write(byteBuf, promise);}
}

重写了write方法,在该方法中进行了数据的序列化操作。具体来说,我们使用Java内置的序列化方式将msg对象序列化为字节数组serializedData,然后将序列化后的数据写入网络通道。

ChannelOutboundHandlerAdapter压缩实现

要通过数据压缩进行处理,基于ChannelOutboundHandlerAdapter接口实现一个压缩处理器。使用DeflaterOutputStream进行数据压缩并发送到网络:

public class CompressionHandler extends ChannelOutboundHandlerAdapter {@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {// 创建输出流,使用DeflaterOutputStream进行数据压缩ByteArrayOutputStream bos = new ByteArrayOutputStream();DeflaterOutputStream dos = new DeflaterOutputStream(bos);// 压缩数据dos.write((byte[]) msg);dos.finish();// 获取压缩后的数据byte[] compressedData = bos.toByteArray();// 将压缩后的数据写入网络通道ByteBuf byteBuf = ctx.alloc().buffer();byteBuf.writeBytes(compressedData);ctx.write(byteBuf, promise);}
}

同样也是重写了write方法,在该方法中进行了数据的压缩操作。我们使用DeflaterOutputStream将原始数据(byte[]) msg进行压缩,然后将压缩后的数据写入网络通道。

LengthBasedEncoder编码器

要实现Netty中的编码器,你可以自定义一个类并实现MessageToByteEncoder接口。展示了如何编写一个基于字符串的编码器:

public class LengthBasedEncoder extends MessageToByteEncoder<String> {@Overrideprotected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception {byte[] data = msg.getBytes(StandardCharsets.UTF_8);int length = data.length;out.writeInt(length);out.writeBytes(data);}
}

encode方法中,我们首先将字符串转换为字节数组,使用UTF-8字符集进行编码。然后,我们获取字节数组的长度,并将其写入输出ByteBuf。最后,我们将字节数组写入输出缓冲区。

注意,上述示例中使用的是字符串编码器,你可以根据实际需求替换成其他类型的编码器。同时,也请确保在创建ByteBuf对象时使用适当的Allocator,以获取更高效的内存分配和释放。

通过将自定义的编码器StringEncoder添加到NettyChannelPipeline中,作为ChannelOutboundHandler使用,你就可以在数据发送前将字符串编码为字节并写入网络通道中了。

解码过程阶段

解码的代码和编码的代码就是一个镜像操作和处理,在这里就进行赘余了,相信小伙伴都可以实现,如果真的有不会实现的,可以评论区留言告诉我,我把完整代码给你们。
在这里插入图片描述
对于 TCP 通信而言,粘包是很正常的现象,因此 decoder 必须处理粘包问题。LengthFrameDecoder 是一个支持粘包处理的decoder 类抽象,可基于基于长度的解码器的实现方式进行控制。

处理器链的建立

通过处理器链,Netty框架可以非常灵活地处理不同类型的事件,在Netty中,我们可以通过ChannelPipeline来建立处理器链。ChannelPipeline是一个用于管理和执行处理器的容器,它负责处理入站和出站的事件,并将这些事件传递给适当的处理器。

创建ChannelPipeline对象
ChannelPipeline pipeline = channel.pipeline();
ChannelPipeline中添加处理器
pipeline.addLast("handler1", new Handler1());
pipeline.addLast("handler2", new Handler2());

这里的 "handler1""handler2" 是处理器的名称,可以根据需要进行命名。

添加的顺序形成处理器链

数据将按照顺序在处理器之间传递。最后一个添加的处理器将是数据的出站处理器,第一个添加的处理器将是数据的入站处理器。

ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new MyHandler());

通过建立处理器链,可以根据需要按照一定的顺序和逻辑处理数据。

未完待续

由于篇幅过长,本文就到这里为止。下一篇文章将继续介绍《【分布式技术专题】「探索高性能远程通信」基于Netty的分布式通信框架实现(Dispatcher和EventListener)(下)》,并详细说明剩下的内容。敬请期待!

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

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

相关文章

wireshark利用sshdump自身组件进行远程实时抓包过滤

引言 以前在不了解wireshark可以远程抓包的时间&#xff0c;经常通过tcpdump在远程linux主机将抓包文件保存下来后&#xff0c;然后拖拽入windows中再打开&#xff0c;进行分析查看。 此过程比较繁琐&#xff0c;也不够实时。比较常用的抓包动作是仅出现某特征的报文后&#…

数据结构与算法:复杂度

友友们大家好啊&#xff0c;今天开始正式学习数据结构与算法有关内容&#xff0c;后续不断更新数据结构有关知识内容&#xff0c;希望多多支持&#xff01; 数据结构&#xff1a; 数据结构是用于存储和组织数据的方式&#xff0c;以便可以有效地访问和修改数据。不同的数据结构…

1.23神经网络框架(sig函数),逆向参数调整法(梯度下降法,链式法则(理解,及处理多层神经网络的方式))

框架 输入层 隐藏层 存在一个阈值&#xff0c;如果低于某一阈值就不激活&#xff1b;高于了就激活 输出层 逆向参数调整方法 初始阶段&#xff0c;随机设置权重值w1,w2 依据训练集 两个数学方法 &#xff08;梯度下降、链式法则&#xff09; 调参借助两个数学方法 当导数为…

2024.1.27 GNSS 学习笔记

1.精确的描述轨道的一组数据(星历)是实现精确定位与导航的基础。 2.GNSS卫星广播星历的提供方式一般有两种&#xff1a;一种是提供开普勒轨道参数和必要的轨道摄动改正项参数&#xff0c;如GPS、BDS、Galileo三大系统采用此种模式&#xff0c;还有QZSS系统&#xff1b;另一种是…

Spring Cloud 之Config详解

大家好&#xff0c;我是升仔 在微服务架构中&#xff0c;统一的配置管理是维护大规模分布式系统的关键。Spring Cloud Config为微服务提供集中化的外部配置支持&#xff0c;它可以与各种源代码管理系统集成&#xff0c;如Git、SVN等。本文将详细介绍如何搭建配置服务器、管理客…

用ASM HEMT模型提取GaN器件的参数

标题&#xff1a;Physics-Based Multi-Bias RF Large-Signal GaNHEMT Modeling and Parameter Extraction Flow (JEDS 17年) 模型描述 该模型的核心是对表面势&#xff08;ψ&#xff09;及其随施加的栅极电压&#xff08;Vg&#xff09;和漏极电压&#xff08;Vd&#xff09…

C++ STL中list迭代器的实现

list 的模拟实现中&#xff0c;重难点在于迭代器功能的实现&#xff0c;因此本文只围绕 iterator 及 const_iterator 的设计进行介绍&#xff0c;其余如增删查改则不再赘述——在C语言的基础上&#xff0c;这些都非常简单。 与 string / vector 不同&#xff0c;list 的节点原生…

【时间安排】

最近刚刚回到家&#xff0c;到家就是会有各种事情干扰&#xff0c;心里变乱人变懒的&#xff0c;而要做的事情也要继续&#xff0c;写论文&#xff0c;改简历&#xff0c;学习新技能。。 明天后天两天写论文改简历 周一&#xff08;早上去城市书房&#xff0c;可能吵一点戴个耳…

【深度学习:开源BERT】 用于自然语言处理的最先进的预训练

【深度学习&#xff1a;开源BERT】 用于自然语言处理的最先进的预训练 是什么让 BERT 与众不同&#xff1f;双向性的优势使用云 TPU 进行训练BERT 结果让 BERT 为您所用 自然语言处理 &#xff08;NLP&#xff09; 面临的最大挑战之一是训练数据的短缺。由于 NLP 是一个具有许多…

C#学习(十一)——Array和Collection

一、集合 集合重要且常用 孤立的数据是没有意义的&#xff0c;集合可以作为大量数据的处理&#xff0c;可进行数据的搜索、迭代、添加、删除。 C#中&#xff0c;所有集合都必须实现ICollection接口&#xff08;数组Array除外&#xff09; 集合说明Array数组&#xff0c;固定长…

【GitHub项目推荐--基于 AI 的口语训练平台】【转载】

Polyglot Polyglot 是一个开源的基于 AI 的口语训练平台客户端&#xff0c;可以在 Windows、Mac 上使用。 比如你想练习英语口语&#xff0c;只需在该平台配置一个虚拟的 AI 国外好友&#xff0c;你可以通过发语音的方式和 AI 好友交流&#xff0c;通过聊天的方式提升你的口…

中仕教育:事业单位考试考什么?

事业单位考试分为两个阶段&#xff0c;分别是笔试和面试&#xff0c;考试科目包括公共科目和专业科目两部分。 公共科目内容是公共基础知识、职业能力测试或申论。一种形式为&#xff1a;公共基础知识职业能力测试或职业能力测试申论。另一种形式为&#xff1a;公共基础申论。…

c语言基础6

1.逗号表达式 逗号表达式&#xff0c;就是用逗号隔开的多个表达式。 逗号表达式&#xff0c;从左向右依次执行。整个表达式的结果是最后⼀个表达式的结果。 我们来看下面的一个代码&#xff1a; int main() {int a 1;int b 2;int ret (a > b, a b 2, b, b a 1);p…

Nginx实现反向代理负载均衡实验

实验环境&#xff1a; VM REdhat虚拟机&#xff08;192.168.87.5&#xff09;一台、VM Redhat虚拟机&#xff08;192.168.87.3&#xff09;一台、阿里云服务器&#xff08;47.93.79.92&#xff09;一台 实验要求&#xff1a;通过windows浏览器访问192.168.87.5&#xff08;虚…

《合成孔径雷达成像算法与实现》Figure5.19

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

仰暮计划|“她就是用她的一双小脚把我们兄弟姐妹几个拉扯大的”

在残存的一些老物件中&#xff0c;在一些泛黄的相片中&#xff0c;掩藏着岁月的冲刷和青葱的时光。曾经无忧无虑的少女早已白发苍苍&#xff0c;不复青春貌美&#xff1b;曾经在父母面前笑闹的孩子早已变成他人眼中的长辈。 ——题记 她的身影也许并不高大&#xff0c;甚至还略…

Linux编辑器vim(含vim的配置)

文章目录 前言vim的基本概念vim基本操作进入vim模式切换退出vim vim指令vim命令模式指令vim底行模式命令 简单vim配置 前言 本篇文章&#xff0c;小编将介绍Linux编辑器–>vim以及vim的配置。 vim的基本概念 正常/普通/命令模式(Normal mode) 控制屏幕光标的移动&#xf…

Gin 框架之jwt 介绍与基本使用

文章目录 一.JWT 介绍二.JWT认证与session认证的区别2.1 基于session认证流程图2.2 基于jwt认证流程图 三. JWT 的构成3.1 header : 头部3.2 payload : 负载3.2.1 标准中注册的声明 (建议但不强制使用)3.2.2 公共的声明3.2.3 私有的声明3.2.4 定义一个payload 3.3 signatrue : …

【计算机网络】概述|分层体系结构|OSI参考模型|TCP/IP参考模型|网络协议、层次、接口

目录 一、思维导图 二、计算机网络概述 1.计算机网络定义、组成、功能 2.计算机网络分类 3.计算机网络发展历史 &#xff08;1&#xff09;计算机网络发展历史1&#xff1a;ARPANET->互联网 &#xff08;2&#xff09;计算机网络发展历史2&#xff1a;三级结构因特网 …

jenkins对接K8S

创建连接K8S的凭据 查看需要使用到的命名空间 [rootk8s ~]# kubectl get ns |grep arts-system arts-system Active 16d创建service accounts [rootk8s ~]# kubectl create sa jenkins-k8s -n arts-system serviceaccount/jenkins-k8s created [rootk8s ~]# kubectl…