分布式系统通信解决方案:Netty 与 Protobuf 高效应用

news2025/2/24 15:12:57

分布式系统通信解决方案:Netty 与 Protobuf 高效应用

一、引言

在现代网络编程中,数据的编解码是系统设计的一个核心问题,特别是在高并发和低延迟的应用场景中,如何高效地序列化和传输数据对于系统的性能至关重要。随着分布式系统和微服务架构的广泛应用,跨平台、高效的序列化方案变得愈加重要。

Protocol Buffers(简称 Protobuf)是 Google 开发的一个高效的序列化工具。它能够将结构化数据序列化为紧凑的二进制格式,具有以下显著优势:

  1. 高效紧凑:Protobuf 使用二进制格式,比传统的 JSON 和 XML 更紧凑,占用更少的存储空间,传输速度更快,适用于高负载、高频繁的网络通信。
  2. 跨语言支持:Protobuf 支持多种编程语言,包括 Java、Python、C++、Go 等,使得它在异构系统之间传输数据时具有极好的兼容性。
  3. 灵活性强:Protobuf 支持复杂的数据结构,如嵌套对象、列表以及可选和重复字段,使得开发者可以灵活定义数据格式,满足不同的业务需求。

随着 Netty 成为构建高性能网络服务的标准框架之一,如何将 Protobuf 与 Netty 高效结合,利用它们的优势实现快速、高效的网络通信,成为了很多开发者关心的课题。本文将深入探讨如何在 Netty 中使用 Protobuf 实现高效的数据编解码,并通过具体的代码示例演示其应用。


二、Protobuf 的基础知识

2.1 什么是 Protobuf?

Protobuf 是一种语言无关、平台无关的数据序列化协议。它通过定义 .proto 文件来描述数据结构,然后使用 Protobuf 编译器(protoc)生成特定语言的代码来实现数据的序列化与反序列化操作。

Protobuf 提供了一种高效、紧凑的方式来存储和交换数据,与传统的 JSON 和 XML 相比,它更加节省带宽和存储空间,特别适用于高并发、低延迟的网络通信场景。

2.2 Protobuf 的优点

  • 效率高:
    Protobuf 使用二进制格式序列化数据,比 JSON 和 XML 格式更紧凑。解析速度也更快,在大规模的数据传输和存储中具有明显的性能优势。
  • 跨平台支持:
    Protobuf 支持多种编程语言,包括 Java、Python、C++、Go 等,能够在不同平台和技术栈之间无缝传输数据。这使得它在异构系统的集成中非常有用。
  • 结构清晰:
    .proto 文件提供了一种简单、清晰的数据描述方式,所有的数据结构都可以在 .proto 文件中明确地定义。开发者只需关注业务逻辑,而不必过多关心底层的序列化和反序列化细节。
  • 易扩展性:
    Protobuf 支持向现有消息结构中添加新字段而不影响旧的消息解析,这为系统的演进和扩展提供了极大的灵活性。

2.3 Protobuf 的基本工作流程

Protobuf 的使用流程非常简单:

  1. 定义 .proto 文件:描述数据结构(如消息类型、字段名称和数据类型)。
  2. 生成代码:使用 Protobuf 编译器(protoc)将 .proto 文件编译成对应语言的代码。
  3. 序列化与反序列化:在应用程序中,使用生成的代码进行数据的序列化和反序列化。

这种工作流使得 Protobuf 成为在分布式系统、微服务架构和跨平台通信中,处理数据交换的理想选择。


三、在 Netty 中使用 Protobuf

Netty 提供了对 Protobuf 的原生支持,主要通过以下编解码器实现:

  1. ProtobufEncoder: 将消息序列化为二进制数据。
  2. ProtobufDecoder: 将二进制数据反序列化为 Protobuf 对象。

此外,为了解决 TCP 拆包与黏包问题,Netty 中通常配合使用 LengthFieldBasedFrameDecoderLengthFieldPrepender


四、Protobuf 在 Netty 中的基础应用

下面通过一个完整的示例展示如何在 Netty 中结合 Protobuf 实现客户端与服务端的数据传输。

1. Protobuf 工具与 Java 8 的兼容性

Protobuf 编译器(protoc 生成的代码与 Java 运行时兼容。由于 Java 8 是较旧的版本,需要确保以下两点:

  1. 选择的 Protobuf 编译器生成的代码与 Java 8 的字节码兼容。
  2. Protobuf 的运行时库(protobuf-java)版本与生成代码保持一致,并支持 Java 8。

2. 工具包版本推荐

对于 Java 8,可以使用以下 Protobuf 版本:

  • Protobuf 编译器(protoc): 推荐使用 3.19.x 或更早的版本。这些版本生成的代码默认是兼容 Java 8 的。
  • 运行时库(protobuf-java): 确保与 Protobuf 编译器版本一致,例如 3.19.x

Protobuf 3.20.x 及更高版本生成的代码可能默认使用 Java 11 特性(如模块化支持),因此对于 Java 8 不再完全兼容。


3. 下载 Protobuf 编译器

  1. 下载链接:

    • 从 Protobuf Releases 页面选择版本(推荐 3.19.x 或更早版本)。
    • Protobuf 3.19.4 版本

    在这里插入图片描述

    • 下载与操作系统对应的预编译二进制文件(protoc-3.x.x-[platform].zip)。
    • 解压后将 protoc 可执行文件的路径加入系统环境变量。
新建项目

在这里插入图片描述

引入依赖

在 Maven 项目中添加以下依赖:

<dependencies>
    <!-- Netty 核心依赖 -->
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.97.Final</version>
    </dependency>

    <!-- Netty Protobuf 编解码支持 -->
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-codec-protobuf</artifactId>
        <version>4.1.97.Final</version>
    </dependency>

    <!-- Protobuf 运行时库 -->
    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>3.19.4</version> <!-- 与 Protobuf 编译器版本匹配 -->
    </dependency>

    <!-- Protobuf 编译插件(如果需要通过 Maven 编译 .proto 文件) -->
    <dependency>
        <groupId>org.xolstice.maven.plugins</groupId>
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>0.6.1</version>
    </dependency>
</dependencies>

4.2 定义 Protobuf 消息

在使用 Protocol Buffers(Protobuf)时,所有数据的定义都需要通过 .proto 文件进行描述。Protobuf 是一种语言无关的、平台无关的序列化数据结构的方式,能够在不同编程语言之间传输数据。在 Protobuf 中,数据通过消息(message)类型定义,每个字段都有类型和唯一的标识符。

什么是 .proto 文件?

.proto 文件是 Protobuf 的定义文件,其中定义了消息类型、字段的名称、数据类型以及字段的编号等信息。它是 Protobuf 数据序列化和反序列化的基础。每个消息类型可以包含多个字段,每个字段有一个编号,Protobuf 会根据这个编号在序列化时决定字段的顺序。

.proto 文件中,你需要遵循一定的语法规则来定义数据结构。Protobuf 支持多种数据类型,包括基本类型(如 int32stringbool 等)以及复合类型(如 messageenumrepeated)。

Protobuf 文件示例

以下是拆分后的两个 .proto 文件:

  1. inventory_request.proto
syntax = "proto3";

package com.example.protobuf;
option java_outer_classname = "InventoryRequestModel";
// InventoryRequest 消息定义
message InventoryRequest {
    string product_id = 1; // 产品 ID
    int32 quantity = 2;    // 请求的数量
    string operation = 3;  // 操作类型:add 或 remove
}

在此文件中,我们定义了一个名为 InventoryRequest 的消息类型:

  • product_id:表示产品的唯一标识符,类型为 string
  • quantity:表示请求的数量,类型为 int32
  • operation:表示操作类型,可能的值有 addremove,类型为 string
  1. inventory_response.proto
syntax = "proto3";

package com.example.protobuf;
option java_outer_classname = "InventoryResponseModel";
// InventoryResponse 消息定义
message InventoryResponse {
    string product_id = 1; // 产品 ID
    bool success = 2;      // 操作是否成功
    string message = 3;    // 响应消息
}

在此文件中,我们定义了一个名为 InventoryResponse 的消息类型:

  • product_id:表示产品的唯一标识符,类型为 string
  • success:表示操作是否成功,类型为 bool
  • message:表示响应消息的详细信息,类型为 string

如何生成 Java 类

通过运行 protoc 编译器,我们可以根据 .proto 文件生成对应的 Java 类。这些类将用于 Java 应用程序中与 Protobuf 消息进行交互。

使用以下命令生成对应的 Java 类:

protoc -I=D:\code\java\myproject\netty-003\src\main\java --java_out=D:\code\java\myproject\netty-003\src\main\java\ D:\code\java\myproject\netty-003\src\main\java\com\example\protobuf\*.proto

此命令做了以下几件事:

  • -I=D:\code\java\myproject\netty-003\src\main\java:指定 .proto 文件的根目录。
  • --java_out=D:\code\java\myproject\netty-003\src\main\java\:指定生成的 Java 类的输出目录。
  • D:\code\java\myproject\netty-003\src\main\java\com\example\protobuf\*.proto:指定要编译的 .proto 文件路径,可以使用通配符 *.proto 来一次性编译多个 .proto 文件。

Protobuf 官方文档

更多关于 Protobuf 文件语法、类型、字段规则等内容,可以参考 Protobuf 的官方文档:

  • Protobuf 官方文档地址:
    https://developers.google.com/protocol-buffers

在文档中,你可以深入了解如何定义不同的数据类型、字段规则以及 Protobuf 的高级用法。


4.3 服务端实现

服务端处理逻辑(Handler):
package com.example.protobuf;
import com.example.protobuf.InventoryRequestModel.InventoryRequest;
import com.example.protobuf.InventoryResponseModel.InventoryResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;


public class ProtobufServerHandler extends SimpleChannelInboundHandler<InventoryRequest> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, InventoryRequest request) {
        System.out.println("收到客户端请求:" + request);

        // 模拟库存处理逻辑
        boolean success = "add".equals(request.getOperation()) || "remove".equals(request.getOperation());
        String message = success ? "操作成功!" : "操作失败,未知操作类型:" + request.getOperation();

        // 构造响应对象
        InventoryResponse response = InventoryResponse.newBuilder()
                .setProductId(request.getProductId())
                .setSuccess(success)
                .setMessage(message)
                .build();

        // 发送响应
        ctx.writeAndFlush(response);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

服务端启动类:
package com.example.protobuf;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;


public class ProtobufServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 4));
                            ch.pipeline().addLast(new ProtobufDecoder(InventoryRequestModel.InventoryRequest.getDefaultInstance()));
                            ch.pipeline().addLast(new LengthFieldPrepender(4));
                            ch.pipeline().addLast(new ProtobufEncoder());
                            ch.pipeline().addLast(new ProtobufServerHandler());
                        }
                    });

            ChannelFuture future = bootstrap.bind(8080).sync();
            System.out.println("服务端已启动,端口:8080");
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}


4.4 客户端实现

客户端处理逻辑(Handler):
package com.example.protobuf;

import io.netty.channel.ChannelHandlerContext;
import com.example.protobuf.InventoryRequestModel.InventoryRequest;
import com.example.protobuf.InventoryResponseModel.InventoryResponse;
import io.netty.channel.SimpleChannelInboundHandler;

import java.nio.charset.StandardCharsets;


public class ProtobufClientHandler extends SimpleChannelInboundHandler<InventoryResponse> {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InventoryRequest request = InventoryRequest.newBuilder()
                .setProductId("P12345")
                .setQuantity(10)
                .setOperation("add")
                .build();

        ctx.writeAndFlush(request);
        System.out.println("客户端已发送请求:" + request);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, InventoryResponse response) {
        System.out.println("收到服务端响应:" + response);
//        System.out.println(new String(response.getMessage().getBytes(StandardCharsets.UTF_8)));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}
客户端启动类:
package com.example.protobuf;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;

public class ProtobufClient {
    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 4));
                            ch.pipeline().addLast(new ProtobufDecoder(InventoryResponseModel.InventoryResponse.getDefaultInstance()));
                            ch.pipeline().addLast(new LengthFieldPrepender(4));
                            ch.pipeline().addLast(new ProtobufEncoder());
                            ch.pipeline().addLast(new ProtobufClientHandler());
                        }
                    });

            ChannelFuture future = bootstrap.connect("localhost", 8080).sync();
            future.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

五、总结

在本篇文章中,我们深入探讨了如何在 Netty 中结合 Protobuf 实现高效的数据编解码。通过详细的代码示例,我们展示了如何利用 Protobuf 轻松进行数据序列化与反序列化,并在 Netty 的高性能网络通信中应用。

1. Protobuf 的优势与应用场景

Protobuf 作为一种高效的二进制序列化协议,具有以下显著优势:

  • 高效紧凑:通过紧凑的二进制格式,Protobuf 可以显著减少带宽消耗和存储需求,在高负载、高频繁的网络通信中表现尤为突出。
  • 跨平台支持:Protobuf 支持多种编程语言,能够在不同语言和平台之间无缝传输数据,特别适合分布式系统和微服务架构中异构系统的数据交换。
  • 灵活扩展:Protobuf 提供灵活的结构扩展机制,能够在不破坏现有系统的情况下,向消息中添加新的字段,保证系统的平稳演化。

这些优势使得 Protobuf 成为高效数据传输的首选,特别是在大规模、高并发、低延迟的应用场景中,如分布式系统、实时数据传输、微服务架构等。

2. Netty 与 Protobuf 的结合

Netty 是一个高性能的网络框架,适用于处理大量并发连接和高效数据传输。通过将 NettyProtobuf 结合,开发者可以在保证高性能的同时,还能有效地进行数据序列化和反序列化。结合 ProtobufEncoderProtobufDecoder,数据的传输效率大大提升,特别是当需要传输大量结构化数据时。

Netty 提供了原生支持,简化了 Protobuf 的使用,只需通过简单的编码解码器配置,就可以实现 Protobuf 消息的高效传输。此外,Netty 的 LengthFieldBasedFrameDecoderLengthFieldPrepender 解码器,帮助我们解决了 TCP 拆包黏包的问题,确保消息完整性和传输的可靠性。

3. 实践中的建议

在实际开发中,结合 NettyProtobuf 的使用,可以进一步优化网络服务的性能:

  • 性能调优:根据业务需求,可以调整 Protobuf 的编解码策略,例如通过压缩数据来减少带宽占用;在高并发场景下,可以使用 Protobuf 的压缩选项来进一步提高传输效率。
  • 多种协议的结合:除了 Protobuf,Netty 还支持其他协议(如 JSON、XML、Thrift 等),你可以根据不同的应用场景,选择适合的数据格式进行组合。
  • 错误处理与安全:在处理实际应用时,务必考虑错误处理和安全性。例如,使用适当的验证机制来防止恶意数据注入,并确保网络连接的安全性(如使用 SSL/TLS 加密)。

4. 高效的跨平台通信

通过本篇博客,你已经学会了如何使用 ProtobufNetty 实现高效、可扩展的跨平台网络通信。无论是在微服务架构中,还是在大规模的分布式系统中,利用这两者的结合,都能够实现高效的消息传递,保证系统的高并发和低延迟特性。

5. 后续学习与扩展

如果你希望进一步优化系统的性能,或在更复杂的场景中使用 NettyProtobuf,可以从以下几个方向进行学习和扩展:

  • Protobuf 高级特性:深入学习 Protobuf 的更多高级特性,如自定义序列化和反序列化逻辑、扩展机制等。
  • Netty 高级用法:学习 Netty 更高级的特性,例如自定义协议处理、事件驱动模型的优化、流量控制等。
  • 性能优化:根据实际需求,结合负载均衡、数据压缩和缓存机制等技术,进一步提高系统的吞吐量和响应速度。

通过不断实践和优化,你将能够构建更加高效、灵活和可扩展的网络服务。

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

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

相关文章

【C++】模板(进阶)

本篇我们来介绍更多关于C模板的知识。模板初阶移步至&#xff1a;【C】模板&#xff08;初阶&#xff09; 1.非类型模板参数 1.1 非类型模板参数介绍 模板参数可以是类型形参&#xff0c;也可以是非类型形参。类型形参就是我们目前接触到的一些模板参数。 //类型模板参数 …

2025年入职/转行网络安全,该如何规划?网络安全职业规划

网络安全是一个日益增长的行业&#xff0c;对于打算进入或转行进入该领域的人来说&#xff0c;制定一个清晰且系统的职业规划非常重要。2025年&#xff0c;网络安全领域将继续发展并面临新的挑战&#xff0c;包括不断变化的技术、法规要求以及日益复杂的威胁环境。以下是一个关…

Golang Gin系列-4:Gin Framework入门教程

在本章中&#xff0c;我们将深入研究Gin&#xff0c;一个强大的Go语言web框架。我们将揭示制作一个简单的Gin应用程序的过程&#xff0c;揭示处理路由和请求的复杂性。此外&#xff0c;我们将探索基本中间件的实现&#xff0c;揭示精确定义路由和路由参数的技术。此外&#xff…

K8S-Pod的环境变量,重启策略,数据持久化,资源限制

1. Pod容器的三种重启策略 注意&#xff1a;k8s所谓的重启容器指的是重新创建容器 cat 07-restartPolicy.yaml apiVersion: v1 kind: Pod metadata:name: nginx-web-imagepullpolicy-always spec:nodeName: k8s233.oldboyedu.com## 当容器异常退出时&#xff0c;始终重启容器r…

常见Arthas命令与实践

Arthas 官网&#xff1a;https://arthas.aliyun.com/doc/&#xff0c;官方文档对 Arthas 的每个命令都做出了介绍和解释&#xff0c;并且还有在线教程&#xff0c;方便学习和熟悉命令。 Arthas Idea 的 IDEA 插件。 这是一款能快速生成 Arthas命令的插件&#xff0c;可快速生成…

Django学习笔记(安装和环境配置)-01

Django学习笔记(安装和环境配置)-01 一、创建python环境 1、可以通过安装Anaconda来创建一个python环境 # 创建一个虚拟python环境 conda create -n django python3.8 # 切换激活到创建的环境中 activate django2、安装django # 进入虚拟环境中安装django框架 pip install …

C# 委托和事件思维导图

思维导图 下载链接腾讯云盘 https://share.weiyun.com/fxBH9ESl

css动画水球图

由于echarts水球图动画会导致ios卡顿&#xff0c;所以纯css模拟 展示效果 组件 <template><div class"water-box"><div class"water"><div class"progress" :style"{ --newProgress: newProgress % }"><…

Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )

一、文件处理 1.1、文件操作的重要性和应用场景 1.1.1、重要性 数据持久化&#xff1a; 文件是存储数据的一种非常基本且重要的方式。通过文件&#xff0c;我们可 以将程序运行时产生的数据永久保存下来&#xff0c;以便将来使用。 跨平台兼容性&#xff1a; 文件是一种通用…

电脑如何访问手机文件?

手机和电脑已经深深融入了我们的日常生活&#xff0c;无时无刻不在为我们提供服务。除了电脑远程操控电脑外&#xff0c;我们还可以在电脑上轻松地访问Android或iPhone手机上的文件。那么&#xff0c;如何使用电脑远程访问手机上的文件呢&#xff1f; 如何使用电脑访问手机文件…

stm32 L051 adc配置及代码实例解析

一 cude的设置&#xff1a; 1. 接口的基本设置&#xff1a; 2. 参数的设置&#xff1a; 二 代码的逻辑&#xff1a; 1. 上面的直接生成代码&#xff0c;然后使用下面源码即可读到adc的数据&#xff1a; void adc_battery_start(void) {uint32_t ADC_value 0;HAL_ADC_Start(&…

Vue3初学之Element Plus Dialog对话框,Message组件,MessageBox组件

Dialog的使用&#xff1a; 控制弹窗的显示和隐藏 <template><div><el-button click"dialogVisible true">打开弹窗</el-button><el-dialogv-model"dialogVisible"title"提示"width"30%":before-close&qu…

C++实现矩阵Matrix类 实现基本运算

本系列文章致力于实现“手搓有限元&#xff0c;干翻Ansys的目标”&#xff0c;基本框架为前端显示使用QT实现交互&#xff0c;后端计算采用Visual Studio C。 目录 Matrix类 1、public function 1.1、构造函数与析构函数 1.2、获取矩阵数值 1.3、设置矩阵 1.4、矩阵转置…

数据库-多表关系

项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构。由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系。 多表关系&#xff1a; 一对多 ( 多对一 ) 一对一 多对多 多表关系 …

【STM32G4xx的CAN驱动记录】

STM32G4xx的CAN驱动记录 CAN说明CAN的波特率计算数据测试总结 本文主要记录了基于STM32G4xx的CAN接口解析某型号雷达数据遇到的问题及规避方法&#xff0c;CAN总线波特率500Kbps&#xff0c;采样点要求80%附近。 注意CAN总线同步段的时间&#xff01;&#xff01;&#xff01; …

Cyber Security 101-Security Solutions-Vulnerability Scanner Overview(漏洞扫描程序概述)

了解漏洞扫描程序及其在实际场景中的工作原理。 任务1&#xff1a;什么是漏洞? 想象一下你住在一个小而可爱的房子里。有一天&#xff0c;你注意到 你的屋顶有很多小洞。如果不处理&#xff0c;这些小孔 可能会导致重大问题。下雨时&#xff0c;水会流过来 这些泄漏并损坏您…

Node.js 完全教程:从入门到精通

Node.js 完全教程&#xff1a;从入门到精通 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;允许开发者在服务器端使用 JavaScript。它的非阻塞 I/O 和事件驱动架构使得 Node.js 非常适合于构建高性能的网络应用。本文将详细介绍 Node.js 的安装、基本语…

【经验分享】ARM Linux-RT内核实时系统性能评估工具

【经验分享】ARM Linux-RT内核实时系统性能评估工具 前言下载和编译方法常用工具介绍总结 前言 最近在研究Linux-RT实时系统&#xff0c;介绍下常用的实时系统的性能评估工具。 下载和编译方法 用git下载 git clone git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.…

C++ ——— 模拟实现 vector 类

目录 vector 类的框架 无参数的构造函数 析构函数 获取有效数据个数 获取容量 重载 [] 运算符 可读可写版本 只可读版本 扩容 尾插 实现迭代器 可读可写版本 只可读版本 自定义设置size长度和内容 在任意位置插入 删除任意位置的数据 赋值重载 vector 类的框…

02内存结构篇(D4_JVM内存分配机制)

目录 一、对象的创建 1. 类加载检查 2. 分配内存 3. 初始化零值 4. 设置对象头 32位对象头 64位对象头 5. 执行方法 二、对象大小与指针压缩 三、对象内存分配 1. 对象内存分配流程图 2. 对象栈上分配 3.3 对象在Eden区分配 3.4 大对象直接进入老年代 3.5 长期存…