1. Netty核心功能与线程模型详解

Netty

  • 1. 认识Netty
  • 2. 第一个Netty程序
  • 3. Netty组件
    • 3.1 EventLoop和EventLoopGroup
    • Channel
    • ChannelPipeline和ChannelHandlerContext
    • ChannelPipeline中ChannelHandler
    • ChannelPipeline

本文是按照自己的理解进行笔记总结,如有不正确的地方,还望大佬多多指点纠正,勿喷。

课程内容:

01、Netty核心组件快速了解
02、Hello,Netty!
03、深入理解Channel、EventLoop(Group)
04、深入理解EventLoop和EventLoopGroup
05、ChannelHandler和它的适配器
06、ChannelPipeline辨析
07、ChannelHandlerContext辨析
08、用Netty解决TCP粘包/半包
09、Netty中的编解码器
10、实战Netty快速实现Web服务器
11、序列化框架Netty集成实战
12、Netty中的单元测试

1. 认识Netty

Netty 4.1.42.Final版本进行

<dependency>
   <groupId>io.netty</groupId>
   <artifactId>netty-all</artifactId>
   <version>4.1.42.Final</version>
   <scope>compile</scope>
</dependency>

基于Netty的知名项目

  • 数据库:Cassandra
  • 大数据处理:Spark、Hadoop
  • 消息中间件:RocketMQ
  • 检索:Elasticsearch
  • 框架:gRPC、Apache Dubbo、Spring5 WebFlux
  • 分布式协调器:ZooKeeper

Netty的优势

  1. API使用简单,开发门槛低;
  2. 功能强大,预置了多种编解码功能,支持多种主流协议;
  3. 定制能力强,可以通过ChannelHandler对通信框架进行灵活地扩展;
  4. 性能高,通过与其他业界主流的NIO框架对比,Netty的综合性能最优;
  5. 成熟、稳定,Netty修复了已经发现的所有JDK NIO BUG,业务开发人员不需要再为NIO的BUG而烦恼;
  6. 社区活跃,版本迭代周期短,发现的BUG可以被及时修复,同时,更多的新功能会加入;
  7. 经历了大规模的商业应用考验,质量得到验证。

为什么不用Netty5 ?
Netty5有两个重大改变:支持AIO(异步编程,就是要回调),将线程模型改成了favk/join。通过测试发现其实对性能的提高不是很大,几乎不明显。

因为Netty5还处于Alpha1版本,几乎停止维护了

为什么Netty使用NIO而不是AIO?
Linux下的AIO是一个伪AIO,Linux下的AIO性能也不如NIO的强。

为什么不用Mina ?

其实根据诞生关系是Netty的诞生稍微比Mina早了那么一点,这个Netty与Mina是同一个作者,这个作者在完成了Mina之后又投身于Netty种了,相当于Mina处于缺少维护的状态。并且Netty之后发布的版本的性能都比Mina优秀,因此就没有使用Mina

2. 第一个Netty程序

Netty的核心组件初步认识

  • Bootstrap、EventLoop(Group)、Channel
  • 事件和ChannelHandler、ChannelPipeline
  • ChannelFuture

Bootstrap是Netty框架启动类和主入口类。Bootstrap分为服务端的与客户端的,

在 Netty 中,Channel 是网络通信的基本概念和抽象。它代表着一个开放的连接,可以进行数据的读写和事件的处理。
具体来说,Channel 可以理解为应用程序与网络套接字之间的通道,它提供了以下主要功能:

  1. 数据的读写:通过 Channel,应用程序可以从网络中读取数据或将数据写入网络。它提供了高效的读写操作,支持异步非阻塞的 I/O 操作。可以通过 Channel 的读写方法来实现数据的传输和交换。
  2. 事件的处理:Channel 是一个事件驱动的实体,它可以处理各种网络事件,例如连接建立、数据到达、写就绪等。通过注册不同类型的事件处理器(ChannelHandler),应用程序可以根据需要处理这些事件,执行相应的逻辑处理。
  3. 状态的管理:Channel 提供了连接的状态管理,包括打开、关闭、活动状态等。应用程序可以通过 Channel 的状态变化事件进行相应的处理,例如连接建立或断开时的处理操作。
  4. 通道的配置:Channel 可以进行各种配置,如设置缓冲区大小、接收和发送缓冲区的设置、超时设置等。通过配置 Channel,可以调整网络通信的性能和行为。
    总之,Channel 在 Netty 中扮演着非常重要的角色,它是应用程序与网络之间的桥梁,提供了数据读写、事件处理和状态管理等功能。通过使用 Channel,开发者可以方便地进行网络编程,实现高性能和可靠的网络通信。

EventLoop(Group)
在 Netty 中,EventLoop 是用于处理 I/O 事件和任务的线程。它是 Netty 异步事件驱动的核心组件,负责管理 Channel 的生命周期、处理事件和执行任务。
EventLoop 在 EventLoopGroup 中扮演着重要角色,而 EventLoopGroup 则是一组维护和管理 EventLoop 的容器。一般情况下,一个应用程序只需要一个 EventLoopGroup,而其中的多个 EventLoop 可以同时处理多个 Channel 的 I/O 操作。
EventLoop 的主要功能包括:

  1. I/O 事件的处理:EventLoop 负责处理 Channel 的 I/O 事件,如数据的读写、连接的建立和关闭等。当一个 I/O 事件发生时,EventLoop 会调用相应的 ChannelHandler 处理事件,并触发相应的回调方法。通过事件驱动的方式,实现了高效的异步非阻塞 I/O。
  2. 任务的执行:除了处理 I/O 事件外,EventLoop 还可以执行用户自定义的任务。这些任务可以是一些耗时的计算、定时任务、事件调度等。通过将任务提交给 EventLoop,可以在事件循环中异步执行,避免了阻塞主线程的情况。
  3. 定时任务的处理:EventLoop 提供了定时任务的调度和执行,支持在一定的时间间隔或固定的时间点执行任务。这对于需要定时执行一些操作的应用场景非常有用,例如心跳检测、定时数据刷新等。

需要注意的是,EventLoop 在内部维护一个事件循环(Event Loop),它会不断地轮询 I/O 事件和任务,以便及时处理。每个 EventLoop 都有一个独立的线程来执行这个循环,确保了并发的安全性。

总之,EventLoop 是 Netty 中负责处理 I/O 事件和任务的线程,通过事件驱动的方式实现了高效的异步非阻塞 I/O。它在 EventLoopGroup 中起着重要的作用,为应用程序提供了高性能和可扩展的网络编程能力。

在 Netty 中,事件(Event)、ChannelHandler 和 ChannelPipeline 是实现高效网络通信的重要组件。

  1. 事件(Event):事件是 Netty 中的核心概念,它代表了网络通信过程中发生的各种状态和操作,如连接建立、数据到达、数据写就绪等。Netty 使用事件来驱动整个网络通信过程,通过触发和处理事件来实现异步的、非阻塞的网络通信。
  2. ChannelHandler:ChannelHandler 是用于处理事件和执行业务逻辑的组件。它定义了一组回调方法,如 channelRead()、channelActive()、channelInactive() 等,用于处理不同类型的事件。开发者可以实现自己的 ChannelHandler,并将其注册到 ChannelPipeline 中,以便在特定事件发生时执行相应的逻辑处理。
  3. ChannelPipeline:ChannelPipeline 是 ChannelHandler 的容器,它负责管理和执行 ChannelHandler 的调用顺序。每个 Channel 都会有一个对应的 ChannelPipeline,用于处理该 Channel 上的事件和数据。当一个事件被触发时,ChannelPipeline 会按照预定的顺序依次调用注册的 ChannelHandler 来处理事件。通过配置不同的 ChannelHandler,可以实现数据的编解码、数据处理、安全认证等功能。

ChannelPipeline 的设计遵循了责任链模式,每个 ChannelHandler 只负责自己关心的事件,通过调用下一个 ChannelHandler 来传递事件和数据。这样可以实现组件的解耦和灵活的功能扩展。

通过将不同的 ChannelHandler 注册到 ChannelPipeline 中,可以构建一个处理器链,每个处理器负责特定的功能。数据在经过 ChannelPipeline 时,会按照处理器链的顺序依次经过每个处理器,最终被发送到合适的目标。

总结来说,事件、ChannelHandler 和 ChannelPipeline 是 Netty 中实现高效网络通信的核心组件。事件用于驱动整个网络通信过程,ChannelHandler 用于处理事件和执行业务逻辑,而 ChannelPipeline 则是管理和执行 ChannelHandler 的调用顺序,实现了组件的解耦和灵活的功能扩展。通过合理配置和使用这些组件,可以实现高性能、可扩展的网络应用。

在 Netty 中,ChannelFuture 是用于异步操作结果的表示和处理的对象。它表示一个尚未完成的 I/O 操作,可以通过 ChannelFuture 来获取操作的结果、添加监听器以及执行后续的操作。
ChannelFuture 提供了以下主要功能:

  1. 异步操作的结果:ChannelFuture 可以获取异步操作的结果,如数据的发送、连接的建立等。它提供了方法来判断操作是否完成,获取操作的成功或失败状态,以及获取操作返回的结果对象。
  2. 添加操作完成的监听器:可以通过 ChannelFuture 添加一个或多个监听器,以便在操作完成后执行相应的操作。例如,可以添加一个监听器来处理操作完成时的逻辑,或者添加一个监听器来处理操作失败时的错误处理。通过监听器,可以对异步操作的结果进行处理。
  3. 等待和同步操作:可以通过 ChannelFuture 进行等待和同步操作,即阻塞当前线程,直到操作完成。这对于需要等待操作结果并进行后续处理的情况非常有用。可以使用 ChannelFuture 的一些方法,如 await()、sync() 等来实现等待和同步操作。
  4. 链式操作:ChannelFuture 支持链式操作,可以在一个操作完成后继续执行下一个操作。通过调用 ChannelFuture 的一些方法,如 addListener()、addListener(ChannelFutureListener) 等,可以实现链式操作的编写,简化了代码的编写。

总之,ChannelFuture 在 Netty 中用于表示和处理异步操作的结果。通过它,可以获取操作的结果、添加监听器来处理操作完成后的逻辑,进行等待和同步操作,以及实现链式操作。它提供了灵活的方式来处理和管理异步操作,使得网络编程更加简洁和高效。

在这里插入图片描述

Hello,Netty! 我们的第一个Netty程序

首先导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ding</groupId>
    <artifactId>netty</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>netty</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.6.2</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.42.Final</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

只要使用Netty,下面这个代码是必写的,唯一不同的是每个应用的handler不太一样。

package com.ding.nettybasic;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

public class EchoServer {
    private static final Logger LOG = LoggerFactory.getLogger(EchoServer.class);

    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws InterruptedException {
        int port = 9999;
        EchoServer echoServer = new EchoServer(port);
        LOG.info("服务器即将启动");
        echoServer.start();
        LOG.info("服务器关闭");
    }

    private void start() throws InterruptedException {
        /*线程组*/
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            /*服务端启动必备*/
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    .channel(NioServerSocketChannel.class)/*指定使用NIO的通信模式*/
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });
            /*异步绑定到服务器,sync()会阻塞到完成*/
            ChannelFuture f = b.bind().sync();
            /*阻塞当前线程,知道服务器的ServerChannel被关闭*/
            f.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully().sync();
        }
    }
}

SocketChannel在与业务流转之间还有一个Buffer,因此这个里面也要有一个Buffer

在这里插入图片描述

package com.ding.nettybasic;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf in = (ByteBuf)msg;
        System.out.println("server accept:"+in.toString(CharsetUtil.UTF_8));
        ctx.writeAndFlush(in);
        ctx.close();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("连接已建立");
        super.channelActive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
package com.ding.nettybasic;

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.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

public class EchoClient {
    private static final Logger LOG = LoggerFactory.getLogger(EchoClient.class);

    private final int port;
    private final String host;

    public EchoClient(int port, String host) {
        this.port = port;
        this.host = host;
    }
    public void start() throws InterruptedException {
        /*线程组*/
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            /*服务端启动必备*/
            Bootstrap b = new Bootstrap();
            b.group(group)
                .channel(NioSocketChannel.class)/*指定使用NIO的通信模式*/
                .remoteAddress(new InetSocketAddress(host,port))
                .handler(new ChannelInitializer<SocketChannel>() {
                     @Override
                     protected void initChannel(SocketChannel ch) throws Exception {
                         ch.pipeline().addLast(new EchoClientHandler());
                     }
                 });
            /*异步绑定到服务器,sync()会阻塞到完成*/
            ChannelFuture f = b.connect().sync();
            /*阻塞当前线程,知道服务器的ServerChannel被关闭*/
            f.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new EchoClient(9999,"127.0.0.1").start();
    }
}
package com.ding.nettybasic;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        /*读取网络数据后进行业务处理,并关闭连接*/
        System.out.println("client Accept" + msg.toString(CharsetUtil.UTF_8));
        /*关闭连接*/
        ctx.close();
    }

    /*channel活跃后,做业务处理*/
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Netty",CharsetUtil.UTF_8));
    }
}

在这里插入图片描述
在这里插入图片描述

3. Netty组件

3.1 EventLoop和EventLoopGroup

关系说明

  • 一个EventLoopGroup包含一个或者多个EventLoop;
  • 一个EventLoop在它的生命周期内只和一个Thread 绑定;
  • 所有由EventLoop 处理的I/O事件都将在它专有的Thread上被处理;

在这里插入图片描述

在这里插入图片描述

Channel

  • Channel-Socket;
  • EventLoop—控制、多线程处理、并发;

在这里插入图片描述

ChannelPipeline和ChannelHandlerContext

ChannelPipeline 提供了ChannelHandler链的容器,并定义了用于在该链上传播入站和出站事件流的APl。

ChannelHandler 的生命周期

在这里插入图片描述
ChannelHandler 的生命周期

在ChannelHandler被添加到ChannelPipeline 中或者被从ChannelPipeline中移除时会调用下面这些方法。这些方法中的每一个都接受一个ChannelHandlerContext参数。

handlerAdded当把 ChannelHandler 添加到ChannelPipeline 中时被调用
handlerRemoved当从ChannelPipeline中移除ChannelHandler时被调用
exceptionCaught当处理过程中在 ChannelPipeline中有错误产生时被调用

ChannelPipeline中ChannelHandler

Netty会把出站Handler和入站Handler放到一个Pipeline中,数据结构上是一个双向链表

在这里插入图片描述

ChannelPipeline

在这里插入图片描述

那么分属出站和入站不同的Handler,在业务没要求的情况下是可以不考虑顺序的。
而同属一个方向的Handler则是有顺序的,因为上一个Handler处理的结果往往是下一个Handler的要求的输入。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开源免费的多数据库工具Chat2DB

Chat2DB v1.0.11使用 当前使用的版本为1.0.11&#xff0c;目前已经更新到2.0.0版本。 一.Chat2DB介绍 Chat2DB 是一款开源免费的多数据库客户端工具。 能够将自然语言转换为SQL&#xff0c;也可以将SQL转换为自然语言。 支持windows、mac本地安装&#xff0c;也支持服务器端…

哈工大计算机网络课程网络层协议详解之:Internet路由BGP协议详解

哈工大计算机网络课程网络层协议详解之&#xff1a;BGP协议详解 在之前的网络层协议中&#xff0c;我们介绍了Internet网络两个自治系统内的路由协议&#xff1a;RIP协议和OSPF协议。这两个协议应该来说是自治系统内协议的两个代表性协议&#xff0c;前一个基于距离向量路由算…

vue项目业务实现,视频监控-文件流,大屏适配方案(v-scale-screen),websocket前端

最近把以前的业务场景及解决方案整理了一下&#xff0c;具体实现的工具如下&#xff1a; 监控-视频文件流>video.js videojs-contrib-hls 大屏适配方案> v-scale-screen websocket>sockjs-client webstomp-client 视频监控-文件流 使用方法 下载video插件&#xf…

异步交互技术Ajax

Ajax 概念&#xff1a;Asynchronous JavaScr And XML 异步的JavaScript和XML作用&#xff1a; 数据交换&#xff1a;通过Ajax可以给服务器发送请求&#xff0c;并获取服务响应的数据异步交互&#xff1a;可以在不重新加载整个页面的情况下&#xff0c;与服务器交换数据并更新部…

第3章 创建项目并初始化业务数据(过程记录)

项目声明和依赖 ECommerceRecommendSystem [pom.xml] 公用的声明、依赖、插件 properties 声明 log4g&#xff1a;处理日志的框架&#xff08;日志的具体实现&#xff09;sel4g&#xff1a;简单日志门面&#xff08;简单日志的接口&#xff09;mongodb-spark&#xff1a;Mong…

用隐私换便利,,,,,,您配吗?

用隐私换便利,您配吗&#xff1f; 引言 近日&#xff0c;某高校毕业生在校期间窃取学校内网数据&#xff0c;收集全校学生个人隐私信息的新闻引发了人们对互联网生活中个人信息安全问题的再度关注。在大数据时代&#xff0c;算法分发带来了隐私侵犯&#xff0c;在享受消费生活…

TX Text Control .NET for WPF 31.SP3 Crack

.NET WPF 应用程序的文档处理 将文档编辑、创建和 PDF 生成添加到您的 WPF 应用程序中。 视窗用户界面 功能齐全的文档编辑器 TX Text Control 是一款免版税、完全可编程的丰富编辑控件&#xff0c;它在专为 Visual Studio 设计的可重用组件中为开发人员提供了广泛的文字处理功…

Matlab学习-轨迹热力图绘制

Matlab学习-轨迹热力图绘制 参考链接&#xff1a; MathWork-scatter函数使用 问题需求&#xff1a; 需要将轨迹上的点另一维信息同时显示在图上&#xff0c;比如横纵向误差等&#xff0c;这个时候画轨迹与误差的热力图就能很好同时反应位置和定位误差之间的关系&#xff1b;…

CSS圆角进化论

CSS圆角发展过程 大致经历了3个阶段&#xff0c;包括&#xff1a; 背景图片实现圆角CSS2.0标签模拟圆角CSS3.0圆角属性&#xff08;border-radius属性)实现圆角 ☛背景图片实现圆角&#xff1a;使用背景图片实现圆角的方式很多&#xff0c;实现的方式和圆角的切图方式关系密…

高级篇十六、多版本并发控制(重要)

目录 1、什么是MVCC2、快照读与当前读2.1 快照读2.2 当前读 3、复习3.1 隔离级别3.2 隐藏字段、Undo Log版本链 4、MVCC实现原理之ReadView4.1 什么是ReadView&#xff1f; 1、什么是MVCC MVCC &#xff08;Multiversion Concurrency Control&#xff09;&#xff0c;多版本并…

电脑出现0xC1900101错误怎么办?

在更新或安装Windows操作系统时&#xff0c;有时系统会提示出现了0xC1900101错误。这个错误的出现通常是源于与驱动程序相关的错误所致。那么当电脑出现0xC1900101错误时该怎么办呢&#xff1f; 为什么会出现错误代码0xC1900101&#xff1f; 通常情况下&#xff0c;有以下几个…

error: exportArchive: No signing certificate \“Mac Development\“ found

error: exportArchive: No signing certificate “Mac Development” found UNIAPP打包又遇到这个问题了, 证书过期续期的时候又遇到这个问题了(之前遇到过解决了,时间长忘了),记录一下,报错信息 error: exportArchive: No signing certificate \"Mac Development\"…

5.8.8 TCP流量控制

5.8.8 TCP流量控制 计算机网络的流量控制实际上是调节发送方的速率使得接收方能够及时处理的一个过程。 在TCP中采用的是大小可变的滑动窗口的方式进行流量控制&#xff0c;窗口大小的单位是字节。 如图 根据接收方的接收能力&#xff0c;通过接收窗口rwnd可以实现一个端到端…

C语言王国探险记之字符串+注释

王国探险记系列 文章目录&#xff08;3&#xff09; 前言 一&#xff0c;什么是字符串呢&#xff1f; 1&#xff0c;那C语言是怎么表示字符串的呢? "hello world.\n" 2&#xff0c;证明字符串的结束标志是一个 \0 的转义字符 3&#xff0c;证明字符串的结束标…

基于springboot+Redis的前后端分离项目(二)-【黑马点评】

&#x1f381;&#x1f381;资源文件分享 链接&#xff1a;https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwdeh11 提取码&#xff1a;eh11 商户查询缓存&#xff0c;缓存更新策略&#xff0c;缓存穿透 商户查询缓存a.什么是缓存1.为什么要使用缓存2.如何使用缓存 b.添加商…

微信小程序分包

原生小程序分包和 uniapp 小程序分包差不多。 分包只是在原有代码结构上&#xff0c;指定那个文件夹属于分包&#xff0c;所以&#xff0c;页面地址原本路径不会修改。 比如&#xff0c;将pages/mine设为分包&#xff0c;mine下面的有页面地址pages/mine/index/index&#xf…

系统盘空间不足怎么清理?Win11系统盘瘦身的方法

系统盘空间不足怎么清理&#xff1f;当我们的电脑使用久了&#xff0c;就会有大量的垃圾文件堆积&#xff0c;会给系统盘空间带来很大的压力&#xff0c;容易出现系统运行卡顿的情况&#xff0c;对此我们需要对系统盘进行一次大扫除。本期教程小编将为大家分享Win11系统盘瘦身的…

20本期刊影响因子上涨,7月SCI/SSCI/AHCI/EI刊源表已更新!

2023年7月SCI/SSCI/AHCI/EI期刊目录更新 2023年6月28日发布的最新《期刊引证报告》中&#xff0c;我处合作期刊中&#xff0c;7月刊源表有20本期刊影响因子上涨&#xff0c;同时新增多本快刊&#xff01; 重磅&#xff01;2023年JCR正式发布&#xff08;附影响因子名单下载&a…

自定义MVC引用XML配置文件实现

目录 前言 自定义MVC实现 1. 导入XML配置文件 2. 导入XML解析建模 3. 优化中央控制器 3.1 修改DisPathServlet中init初始化方法 3.2 修改ActionServlet逻辑处理流程 3.3 通过反射机制实例化子控制器类 3.4 中央控制器将请求委托给子控制器处理 3.5 根据请求结果码跳…

【物联网无线通信技术】802.11无线安全认证

本文由简入繁介绍了IEEE802.11i无线局域网安全技术的前世今生&#xff0c;帮助路由器开发者对WLAN的加密安全策略有一个概念上的认知&#xff0c;能够更好地分析STA掉线以及漫游等问题。 目录 WEP WPA WPA/WPA2-PSK认证过程 802.11i WEP WEP是Wired Equivalent Privacy的简…