Netty Review - 探索Pipeline的Inbound和Outbound

news2024/9/22 15:47:38

文章目录

  • 概念
  • Server Code
  • Client Code
  • InboundHandler和OutboundHandler的执行顺序
    • 在InboundHandler中不触发fire方法
    • InboundHandler和OutboundHandler的执行顺序
    • 如果把OutboundHandler放在InboundHandler的后面,OutboundHandler会执行吗

在这里插入图片描述


概念

在这里插入图片描述

我们知道boss线程监控到绑定端口上有accept事件,此时会为该socket连接实例化Pipeline,并将InboundHandlerOutboundHandler按序加载到Pipeline中,然后将该socket连接(也就是Channel对象)挂载到selector

一个selector对应一个线程,该线程会轮询所有挂载在他身上的socket连接有没有readwrite事件,然后通过线程池去执行Pipeline的业务流

selector如何查询哪些socket连接有readwrite事件,主要取决于调用操作系统的哪种IO多路复用内核

  • 如果是select注意,此处的select是指操作系统内核的select IO多路复用,不是nettyseletor对象),那么将会遍历所有socket连接,依次询问是否有readwrite事件,最终操作系统内核将所有IO事件的socket连接返回给netty进程,当有很多socket连接时,这种方式将会大大降低性能,因为存在大量socket连接的遍历和内核内存的拷贝
  • 如果是epoll,性能将会大幅提升,因为它基于完成端口事件,已经维护好有IO事件的socket连接列表,selector直接取走,无需遍历,也少掉内核内存拷贝带来的性能损耗

Netty中,InboundOutbound是两个重要的概念,用于描述数据在ChannelPipeline中的流动方向。

Inbound(入站)指的是数据从网络传输到应用程序,即数据从远程主机进入本地主机。在ChannelPipeline中,Inbound数据会依次经过Pipeline中的每个ChannelHandler进行处理,直到到达Pipeline的末尾。

Outbound(出站)指的是数据从应用程序传输到网络,即数据从本地主机发送到远程主机。在ChannelPipeline中,Outbound数据会从Pipeline的末尾开始,逆序经过Pipeline中的每个ChannelHandler进行处理,直到到达Pipeline的起始位置。

InboundOutbound的区别在于数据的流动方向。Inbound数据是从网络进入应用程序,而Outbound数据是从应用程序发送到网络。这意味着Inbound数据是应用程序接收和处理外部数据的入口,而Outbound数据是应用程序发送数据到外部的出口。

虽然InboundOutbound描述了数据的不同流动方向,但它们之间也存在联系。在ChannelPipeline中,InboundOutbound数据可以相互影响和交互。例如,一个ChannelHandler可以在处理Inbound数据时生成Outbound数据作为响应,或者在处理Outbound数据时修改Inbound数据的内容。

总结起来,InboundOutbound是描述数据在ChannelPipeline中流动方向的概念。Inbound数据是从网络进入应用程序,Outbound数据是从应用程序发送到网络。它们在ChannelPipeline中相互影响和交互,共同实现网络数据的处理和传输。


Pipeline的责任链是通过ChannelHandlerContext对象串联的,ChannelHandlerContext对象里封装了ChannelHandler对象,通过prev和next节点实现双向链表。Pipeline的首尾节点分别是headtail,当selector轮询到socketread事件时,将会触发Pipeline责任链,从head开始调起第一个InboundHandlerChannelRead事件,接着通过fire方法依次触发Pipeline上的下一个ChannelHandler .

在这里插入图片描述

ChannelHandler分为InbounHandlerOutboundHandler

  • InboundHandler用来处理接收消息
  • OutboundHandler用来处理发送消息。

headChannelHandler既是InboundHandler又是OutboundHandler,无论是read还是write都会经过head,所以head封装了unsafe方法,用来操作socketreadwritetailChannelHandler只是InboundHandlerreadPipleline处理将会最终到达tail


演示之前,我们先附一下代码

Server Code

package com.artisan.pipeline.inout;

import com.artisan.pipeline.inout.handler.*;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class ArtisanEchoServer {

    private int port;

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

    private void run() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {

                            ch.pipeline().addLast(new EchoOutboundHandler3());
                            ch.pipeline().addLast(new EchoOutboundHandler2());
                            ch.pipeline().addLast(new EchoOutboundHandler1());


                            ch.pipeline().addLast(new EchoInboundHandler1());
                            ch.pipeline().addLast(new EchoInboundHandler2());
                            ch.pipeline().addLast(new EchoInboundHandler3());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 10000)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            System.out.println("EchoServer正在启动...");

            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            System.out.println("EchoServer绑定端口:" + port);

            channelFuture.channel().closeFuture().sync();
            System.out.println("EchoServer已关闭.");


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    public static void main(String[] args) {
        int port = 1234;
        if (args != null && args.length > 0) {
            try {
                port = Integer.parseInt(args[0]);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        ArtisanEchoServer server = new ArtisanEchoServer(port);
        server.run();
    }
}
    

6个handler演示如下

package com.artisan.pipeline.inout.handler;

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

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class EchoInboundHandler1 extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println();

        System.out.println("进入 EchoInboundHandler1.channelRead");

        String data = ((ByteBuf) msg).toString(CharsetUtil.UTF_8);
        System.out.println("EchoInboundHandler1.channelRead 收到数据:" + data);
        ctx.fireChannelRead(Unpooled.copiedBuffer("[EchoInboundHandler1] " + data, CharsetUtil.UTF_8));

        System.out.println("退出 EchoInboundHandler1 channelRead");

        System.out.println();

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("[EchoInboundHandler1.channelReadComplete]");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("[EchoInboundHandler1.exceptionCaught]" + cause.toString());
    }
}
    
package com.artisan.pipeline.inout.handler;

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

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class EchoInboundHandler2 extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println();

        System.out.println("进入 EchoInboundHandler2.channelRead");

        String data = ((ByteBuf) msg).toString(CharsetUtil.UTF_8);
        System.out.println("EchoInboundHandler2.channelRead 接收到数据:" + data);
        //ctx.writeAndFlush(Unpooled.copiedBuffer("[第一次write] [EchoInboundHandler2] " + data, CharsetUtil.UTF_8));
        ctx.channel().writeAndFlush(Unpooled.copiedBuffer("测试一下channel().writeAndFlush", CharsetUtil.UTF_8));
        ctx.fireChannelRead(Unpooled.copiedBuffer("[ArtisanEchoOutboundHandler2] " + data, CharsetUtil.UTF_8));

        System.out.println("退出 EchoInboundHandler2 channelRead");

        System.out.println();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("[EchoInboundHandler2.channelReadComplete]读取数据完成");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("[EchoInboundHandler2.exceptionCaught]");
    }
}
    
package com.artisan.pipeline.inout.handler;

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

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class EchoInboundHandler3 extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println();

        System.out.println("进入 EchoInboundHandler3.channelRead");

        String data = ((ByteBuf)msg).toString(CharsetUtil.UTF_8);
        System.out.println("EchoInboundHandler3.channelRead 接收到数据:" + data);
        //ctx.writeAndFlush(Unpooled.copiedBuffer("[第二次write] [EchoInboundHandler3] " + data, CharsetUtil.UTF_8));
        ctx.fireChannelRead(msg);

        System.out.println("退出 EchoInboundHandler3 channelRead");

        System.out.println();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("[EchoInboundHandler3.channelReadComplete]读取数据完成");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("[EchoInboundHandler3.exceptionCaught]");
    }

}
    
package com.artisan.pipeline.inout.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class EchoOutboundHandler1 extends ChannelOutboundHandlerAdapter {


    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("进入 EchoOutboundHandler1.write");

        //ctx.writeAndFlush(Unpooled.copiedBuffer("[第一次write中的write]", CharsetUtil.UTF_8));
//        ctx.channel().writeAndFlush(Unpooled.copiedBuffer("在OutboundHandler里测试一下channel().writeAndFlush", CharsetUtil.UTF_8));
        ctx.write(msg);

        System.out.println("退出 EchoOutboundHandler1.write");
    }

}
    
package com.artisan.pipeline.inout.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class EchoOutboundHandler2 extends ChannelOutboundHandlerAdapter {

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("进入 EchoOutboundHandler2.write");

        //ctx.writeAndFlush(Unpooled.copiedBuffer("[第二次write中的write]", CharsetUtil.UTF_8));
        ctx.write(msg);

        System.out.println("退出 EchoOutboundHandler2.write");
    }
}
    
package com.artisan.pipeline.inout.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class EchoOutboundHandler3 extends ChannelOutboundHandlerAdapter {

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("进入 EchoOutboundHandler3.write");

        ctx.write(msg);

        System.out.println("退出 EchoOutboundHandler3.write");
    }

}
    

Client Code

package com.artisan.netty4.client;

import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;

/**
 * @author 小工匠
 * @version 1.0
 * @description: 客户端启动程序
 * @mark: show me the code , change the world
 */
public class ArtisanClient {

    public static void main(String[] args) throws Exception {
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
        try {
            //创建bootstrap对象,配置参数
            Bootstrap bootstrap = new Bootstrap();
            //设置线程组
            bootstrap.group(eventExecutors)
                    //设置客户端的通道实现类型
                    .channel(NioSocketChannel.class)
                    //使用匿名内部类初始化通道
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //添加客户端通道的处理器
                            ch.pipeline().addLast(new ArtisanClientHandler());
                        }
                    });
            System.out.println("客户端准备就绪");
            //连接服务端
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 1234).sync();
            //对通道关闭进行监听
            channelFuture.channel().closeFuture().sync();
        } finally {
            //关闭线程组
            eventExecutors.shutdownGracefully();
        }
    }
}
    
package com.artisan.netty4.client;

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

/**
 * @author 小工匠
 * @version 1.0
 * @description: 通用handler,处理I/O事件
 * @mark: show me the code , change the world
 */
@ChannelHandler.Sharable
public class ArtisanClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //发送消息到服务端
        ctx.writeAndFlush(Unpooled.copiedBuffer("msg send from client 2 server ", CharsetUtil.UTF_8));
        System.out.println("客户端发消息给服务端结束");

        System.out.println();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //接收服务端发送过来的消息
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("收到服务端" + ctx.channel().remoteAddress() + "的消息:" + byteBuf.toString(CharsetUtil.UTF_8));
    }

}
    

InboundHandler和OutboundHandler的执行顺序

在InboundHandler中不触发fire方法

ArtisanEchoServer#run 中我们先进存在InboundHandler

在这里插入图片描述

在这里插入图片描述

先启动server, 在启动Client,我们测试一下

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

我们可以看到: InboundHandler2没有调用fire事件,InboundHandler3没有被执行

InboundHandler是通过fire事件决定是否要执行下一个InboundHandler,如果InboundHandler没有调用fire事件,那么后续的Pipeline中的Handler将不会执行。

我们来看下源码

在这里插入图片描述


InboundHandler和OutboundHandler的执行顺序

在这里插入图片描述
加入Pipeline的ChannelHandler的顺序如上。

别忘了放开EchoInboundHandler2

 ctx.fireChannelRead(Unpooled.copiedBuffer("[ArtisanEchoOutboundHandler2] " + data, CharsetUtil.UTF_8));

我们来验证下

在这里插入图片描述

执行顺序如上。

InboundHandler1 => InboundHandler2 => OutboundHandler1 => OutboundHander2 => OutboundHandler3 => InboundHandler3

1、InboundHandler是按照Pipleline的加载顺序,顺序执行。

2、OutboundHandler是按照Pipeline的加载顺序,逆序执行。


如果把OutboundHandler放在InboundHandler的后面,OutboundHandler会执行吗

在这里插入图片描述

其中EchoInboundHandler2 先不要给客户端发送数据,先屏蔽掉。

public class EchoInboundHandler2 extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        System.out.println("进入 EchoInboundHandler2.channelRead");

        String data = ((ByteBuf) msg).toString(CharsetUtil.UTF_8);
        System.out.println("EchoInboundHandler2.channelRead 接收到数据:" + data);
//        ctx.writeAndFlush(Unpooled.copiedBuffer("[第一次write] [EchoInboundHandler2] " + data, CharsetUtil.UTF_8));
//        ctx.channel().writeAndFlush(Unpooled.copiedBuffer("测试一下channel().writeAndFlush", CharsetUtil.UTF_8));
        ctx.fireChannelRead(Unpooled.copiedBuffer("[ArtisanEchoOutboundHandler2] " + data, CharsetUtil.UTF_8));


        System.out.println("退出 EchoInboundHandler2 channelRead");

    }
.......
.......
.......

在这里插入图片描述

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

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

相关文章

SSD-FTL算法学习总结1

SSD核心技术&#xff1a;FTL算法。 1、什么是FTL? FTL是Flash Translation Layer&#xff08;闪存转换层&#xff09;&#xff0c;完成主机&#xff08;HOST&#xff09;逻辑地址空间到闪存Flash物理地址空间的翻译,或者说映射&#xff08;Mapping&#xff09;。 FTL算法分成…

发生这种情况 经常导致投资者的痛苦

在这个市场中&#xff0c;什么事会让人痛苦呢&#xff1f;有的投资者马上回答&#xff0c;因为亏损。说实话&#xff0c;如果经过刻意的练习&#xff0c;我们在一定程度上能克服亏损给人带来的痛感。但是有另一种情况也容易为投资者带来痛苦&#xff0c;下面我们就来讨论一下。…

4、RTC 实时时钟Demo(STM32F407)

RTC是个独立的BCD定时器/计数器。RTC 提供一个日历时钟&#xff0c;两个可编程闹钟中断&#xff0c;以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含用于管理低功耗模式的自动唤醒单元。 (RTC实质&#xff1a;一个掉电(主电源)后还继续运行(由VBAT供电)的32位的向上计…

为什么年轻人这么热衷元宇宙NFT?

盘点你们不知道的元宇宙玩法套路&#xff1a;潮玩宇宙、趣玩联盟、潮玩世界 引言&#xff1a;项目圈最常见的一句话&#xff0c;是这样说的“你图的是平台的高利息&#xff0c;而平台图的是你的本金”&#xff0c;这是韭菜人追悔莫及讲的最经典的话&#xff0c;但也有杠精同志讲…

【OJ比赛日历】快周末了,不来一场比赛吗? #12.02-12.08 #15场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-12-02&#xff08;周六&#xff09; #4场比赛2023-12-03…

AWS EC2 如何 使用 SSM会话管理器登陆

首先只有特定版本的OS会默认附带SSM Agent。 预安装了 SSM Agent 的 Amazon Machine Images&#xff08;AMIs&#xff09; - AWS Systems Manager 其次EC的instance role必须有一个叫“AmazonSSMManagedInstanceCore”的策略 如何给IAM User赋权&#xff0c;让他们可以使用SSM…

深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理&#x1f525;如果感觉博主的文章还不错的话&#xff…

zookeeper集群和kafka集群

&#xff08;一&#xff09;kafka 1、kafka3.0之前依赖于zookeeper 2、kafka3.0之后不依赖zookeeper&#xff0c;元数据由kafka节点自己管理 &#xff08;二&#xff09;zookeeper 1、zookeeper是一个开源的、分布式的架构&#xff0c;提供协调服务&#xff08;Apache项目&…

CityEngine2023 根据shp数据构建三维模型并导入UE5

目录 0 引言1 基本操作2 实践2.1 导入数据&#xff08;.shp&#xff09;2.2 构建三维模型2.3 将模型导入UE5 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;CityEngine专栏&#x1f4a5; 标题&#xff1a;CityEngine2023 根据shp数据构建三维模型…

零基础学编程系列,看一下具体中文编程代码是什么样子的

零基础学编程系列&#xff0c;看一下具体中文编程代码是什么样子的 上图 编写一个单选的程序 上图 是单选 按钮的中文编程代码 附&#xff1a;中文编程工具构件工具箱总共22组305个构件&#xff0c;构件明细如下&#xff1a; 文本件16个&#xff1a; &#xff08;普通标签&am…

JDK版本降级,如何重新编译打包项目

目前大部分人使用jdk1.8以及更高版本的jdk&#xff0c;在开发过程中也使用了很多jdk1.8的新特性&#xff0c;但或许还存在一些使用jdk低版本的客户&#xff0c;这时如果我们提供的代码涉及必须高版本jdk才能运行的话&#xff0c;那代码就必须降级&#xff0c;客户才能使用&…

Intellij IDEA 的安装和使用以及配置

IDE有很多种&#xff0c;常见的Eclipse、MyEclipse、Intellij IDEA、JBuilder、NetBeans等。但是这些IDE中目前比较火的是Intellij IDEA&#xff08;以下简称IDEA&#xff09;&#xff0c;被众多Java程序员视为最好用的Java集成开发环境&#xff0c;今天的主题就是IDEA为开发工…

.NET开源的处理分布式事务的解决方案

前言 在分布式系统中&#xff0c;由于各个系统服务之间的独立性和网络通信的不确定性&#xff0c;要确保跨系统的事务操作的最终一致性是一项重大的挑战。今天给大家推荐一个.NET开源的处理分布式事务的解决方案基于 .NET Standard 的 C# 库&#xff1a;CAP。 CAP项目介绍 CA…

由于找不到msvcp120.dll的解决方法,msvcp120.dll修复指南

当你尝试运行某些程序或游戏时&#xff0c;可能会遇到系统弹出的错误消息&#xff0c;提示"找不到msvcp120.dll"或"msvcp120.dll丢失"。这种情况通常会妨碍程序的正常启动。为了帮助解决这一问题&#xff0c;本文将深入讨论msvcp120.dll是什么&#xff0c;…

【C++】了解模板

这里是目录 前言函数模板函数模板的实例化类模板 前言 如果我们要交换两个数字&#xff0c;那么我们就需要写一个Swap函数来进行交换&#xff0c;那如果我们要交换char类型的数据呢&#xff1f;那又要写一份Swap的函数重载&#xff0c;参数的两个类型是char&#xff0c;那我们…

【排序,直接插入排序 折半插入排序 希尔插入排序】

文章目录 排序排序方法的分类插入排序直接插入排序折半插入排序希尔插入排序 排序 将一组杂乱无章的数据按照一定规律排列起来。将无序序列排成一个有序序列。 排序方法的分类 储存介质&#xff1a; 内部排序&#xff1a;数据量不大&#xff0c;数据在内存&#xff0c;无需…

【FPGA图像处理】——DDR仲裁、多输入源拼接、旋转任意角度、突发长度修改、任意地址读取。

前言&#xff1a;做FPGA大赛期间遇到的问题&#xff0c;自己coding过程。 包含&#xff1a;hdmi、摄像头等多输入源的拼接&#xff1b;了解DDR以及多种DMA传输方式&#xff0c;修改底层突发长度以及存储位宽&#xff1b;单输入源任意角度旋转&#xff08;无需降低帧率&#xff…

tex2D使用学习

1. 背景&#xff1a; 项目中使用到了纹理进行插值的加速&#xff0c;因此记录一些自己在学习tex2D的一些过程 2. 代码&#xff1a; #include "cuda_runtime.h" #include "device_launch_parameters.h" #include <assert.h> #include <stdio.h>…

XTU OJ 1339 Interprime 学习笔记

链接 传送门 代码 #include<bits/stdc.h> using namespace std;const int N1e610; //78498 我计算了一下&#xff0c;6个0的范围内有这么多个素数&#xff0c;所以开这么大的数组存素数 //计算的代码是一个循环 int prime[80000]; int a[N],s[N];//s数组是前缀和数组b…

自定义链 SNAT / DNAT 实验举例

参考原理图 实验前的环境搭建 1. 准备三台虚拟机&#xff0c;定义为内网&#xff0c;外网以及网卡服务器 2. 给网卡服务器添加网卡 3. 将三台虚拟机的防火墙和安全终端全部关掉 systemctl stop firewalld && setenforce 0 4. 给内网虚拟机和外网虚拟机 yum安装 httpd…