基于docker搭建pulsar和使用攻略

pulsar

Pulsar是一个由yahoo公司于2016年开源的消息中间件,2018年成为Apache的顶级项目

我们先来看一下架构,从架构来看,和其他的消息中间件差不多,都是有消费者,生产者和broker,唯一一点不同的是pulsar的数据存储是存储在BookKeeper中的。
在这里插入图片描述
在这里插入图片描述

  • Producer:消息生产者,将消息发送到broker。
  • Consumer:消息消费者,从Broker读取消息到客户端,进行消费处理。
  • Broker: 可以看作是pulsar的server,Producer和Consumer都看作是client.消息处理的节点,pulsar的Broker和其他消息中间件的都不一样,他是无状态的没有存储,所以可以无限制的扩展。
  • Bookie: 负责所有消息的持久化,这里采用的是Apache Bookeeper。
  • ZK: 和kafka一样pulsar也是使用zk保存一些元数据,比如配置管理,topic分配,租户等等。
  • Service Discovery:可以理解为Pulsar中的nginx,只用一个url就可以和整个broker进行打交道,当然也可以使用自己的服务发现。客户端发出的读取,更新或删除主题的初始请求将发送给可能不是处理该主题的 broker 。 如果这个 broker 不能处理该主题的请求,broker 将会把该请求重定向到可以处理主题请求的 broker。

安装

接下来我们安装一下,通过UI界面来看一下pulsar。以下是基于docker安装的

下载docker镜像

docker pull apachepulsar/pulsar:latest

启动服务

docker run --name pulsar \
-p 6650:6650 \
-p 8080:8080 \
--mount source=pulsardata,target=/pulsar/data \
--mount source=pulsarconf,target=/pulsar/conf \
-d apachepulsar/pulsar bin/pulsar standalone
  • 6650端口:这是Pulsar Broker的默认二进制协议通信端口。是一个tcp协议。当你需要连接到Pulsar的Broker节点时,通常会使用这个端口。Broker节点是Pulsar的核心组件之一,负责接收和处理消息,以及提供主要的消息传递服务。如果你的应用程序是Pulsar的消息生产者或消费者,并且需要与Pulsar集群的Broker进行通信,那么就会使用6650端口。
  • 8080端口:这是Pulsar Admin服务的默认REST API及Web界面端口。支持的是http协议。当你需要执行管理操作(例如创建或删除租户、命名空间、主题等),或者监控Pulsar集群的健康状况时,通常会使用8080端口。此端口提供了REST API接口以及Web界面,用于管理和监控Pulsar集群。

可视化管理

  • 拉取web可视化管理平台
docker pull apachepulsar/pulsar-manager:latest
  • 生成容器并启动
 
docker run -it \
  --name pulsar-manager \
  -p 9527:9527 -p 7750:7750 \
  --mount source=pulsarmanager,target=/pulsar-manager/pulsar-manager \
  -e SPRING_CONFIGURATION_FILE=/pulsar-manager/pulsar-manager/application.properties \
  apachepulsar/pulsar-manager:latest
  • 9527:这个端口是提供web-ui的端口
  • 7750: 提供rest-api接口,比如初始化管理员用户名密码

设置管理员密码

CSRF_TOKEN=$(curl http://localhost:7750/pulsar-manager/csrf-token)
curl \
   -H 'X-XSRF-TOKEN: $CSRF_TOKEN' \
   -H 'Cookie: XSRF-TOKEN=$CSRF_TOKEN;' \
   -H "Content-Type: application/json" \
   -X PUT http://localhost:7750/pulsar-manager/users/superuser \
   -d '{"name": "admin", "password": "apachepulsar", "description": "test", "email": "username@test.org"}'

通过9527访问界面

在这里插入图片描述
pulsar-manager可以管理多个pulsar服务,可以在这里进行配置pulsar的信息。

在这里插入图片描述
我们看一下面板里面的元素

  • persistent/non-persistentPulsar 提供持久化、非持久化两种主题,如果选择的是非持久化主题的话,所有消息都在内存中保存,如果broker重启,消息将会全部丢失。如果选择的是持久化主题,所有消息都会持久化到磁盘,重启broker,消息也可以正常消费。
  • tenant顾名思义就是租户,pulsar最开始在雅虎内部是作为全公司使用的中间件使用的,需要给topic指定一些层级,租户就是其中一层,比如这个可以是一个大的部门,例如电商中台租户。
  • namespace命名空间,可以看作是第二层的层级,比如电商中台下的订单业务组topic消息队列名字

概念了解

生产者

异步发送

我们上面说了send分为async和sync两种模式,但实际上在pulsar内部sync模式也是采用的async模式,在sync模式下模拟回调阻塞,达到同步的效果,这个在kafka中也是采用的这个模式,但是在rocketmq中,所有的send都是真正的同步,都会直接请求到broker。
基于这个模式,在pulsar和kafka中都支持批量发送,在rocketmq中是直接发送,批量发送有什么好处呢?当我们发送的TPS特别高的时候,如果每次发送都直接和broker直连,可能会做很多的重复工作,比如压缩,鉴权,创建链接等等。比如我们发送1000条消息,那么可能会做1000次这个重复的工作,如果是批量发送的话这1000条消息合并成一次请求,相对来说压缩,鉴权这些工作就只需要做一次。
在这里插入图片描述

负载均衡

在消息队列中通常会将topic进行水平扩展,在pulsar和kafka中叫做partition,在rocketmq中叫做queue,本质上都是分区,我们可以将不同分区落在不同的broker上,达到我们水平扩展的效果。
在我们发送的时候可以自己制定选择partition的策略,也可以使用它默认轮训partition策略。当我们选择了partition之后,我们怎么确定哪一个partition对应哪一个broker呢?
在这里插入图片描述

  • Step1: 我们所有的信息分区映射信息在zk和broker的缓存中都有进行存储。
  • Step2: 我们通过查询broker,可以获取到分区和broker的关系,并且定时更新。
  • Step3: 在pulsar中每个分区在发送端的时候都被抽象成为一个单独的Producer,这个和kafka,rocketmq都不一样,在kafka里面大概就是选择了partition之后然后再去找partition对应的broker地址,然后进行发送。pulsar将每一个partition都封装成Producer,再代码实现上就不需要去关注他具体对应的是哪个broker,所有的逻辑都在producer这个代码里面,整体来说比较干净。

压缩消息

消息压缩是优化信息传输的手段之一,我们通常看见一些大型文件都会是以一个压缩包的形式提供下载,在我们消息队列中我们也可以用这种思想,我们将一个batch的消息,比如有1000条可能有1M的传输大小,但是经过压缩之后可能就只会有几十kb,增加了我们和broker的传输效率,但是与之同时我们的cpu也带来了损耗。Pulsar客户端支持多种压缩类型,如 lz4、zlib、zstd、snappy 等。

broker

接下来我们来说说第二个比较重要的部分Broker,在Broker的设计中pulsar和其他所有的消息队列差别比较大,而正是因为这个差别也成为了他的特点。
首先我们来说说他最大的特点:计算和存储分离。我们在开始的说过Pulsar是下一代消息队列,就非常得益于他这个架构设计,无论是kafka还是RocketMQ,所有的计算和存储都放在同一个机器上,这个模式有几个弊端:

扩展困难:当我们需要扩展的集群的时候,我们通常是因为cpu或者磁盘其中一个原因影响,但是我们却要申请一个可能cpu和磁盘配置都很好的机器,造成了资源浪费。并且kafka这种进行扩展,还需要进行迁移数据,过程十分繁杂。
负载不均衡:当某些partion数据特别多的时候,会导致broker负载不均衡,如下面图,如果某个partition数据特别多,那么就会导致某个broker(轮船)承载过多的数据,但是另外的broker可能又比较空闲。

pulsar计算分离架构能够非常好的解决这个问题:

对于计算:也就是我们的broker,提供消息队列的读写,不存储任何数据,无状态对于我们扩展非常友好,只要你机器足够,就能随便上。扩容Broker往往适用于增加Consumer的吞吐,当我们有一些大流量的业务或者活动,比如电商大促,可以提前进行broker的扩容。
对于存储:也就是我们的bookie,只提供消息队列的存储,如果对消息量有要求的,我们可以扩容bookie,并且我们不需要迁移数据,扩容十分方便。

在这里插入图片描述

Entry,Entry是存储到bookkeeper中的一条记录,其中包含Entry ID,记录实体等。
Ledger,可以认为ledger是用来存储Entry的,多个Entry序列组成一个ledger。
Journal,其实就是bookkeeper的WAL(write ahead log),用于存bookkeeper的事务日志,journal文件有一个最大大小,达到这个大小后会新起一个journal文件。
Entry log,存储Entry的文件,ledger是一个逻辑上的概念,entry会先按ledger聚合,然后写入entry log文件中。同样,entry log会有一个最大值,达到最大值后会新起一个新的entry log文件
Index file,ledger的索引文件,ledger中的entry被写入到了entry log文件中,索引文件用于entry log文件中每一个ledger做索引,记录每个ledger在entry log中的存储位置以及数据在entry log文件中的长度。
MetaData Storage,元数据存储,是用于存储bookie相关的元数据,比如bookie上有哪些ledger,bookkeeper目前使用的是zk存储,所以在部署bookkeeper前,要先有zk集群。

在这里插入图片描述

消费者

订阅模式

订阅模式是用来定义我们的消息如何分配给不同的消费者,不同消息队列中间件都有自己的订阅模式,一般我们常见的订阅模式有:

集群模式:一条消息只能被一个集群内的消费者所消费。
广播模式:一条消息能被集群内所有的消费者消费。

在pulsar中提供了4种订阅模式,分别是独占,灾备,共享,键共享:
在这里插入图片描述

  • 独占:顾名思义只能由一个消费者独占,如果同一个集群内有第二个消费者去注册,第二个就会失败,这个适用于全局有序的消息。
    灾备:加强版独占,如果独占的那个挂了,会自动的切换到另外一个好的消费者,但是还是只能由一个独占。
  • 共享模式:这个模式看起来有点像集群模式,一条消息也是只能被一个集群内消费者消费,但是和rocketmq不同的是,rocketmq是以partition维度,同一个Partition的数据都会被发到一个机器上。在Pulsar中消费不会以partition维度,而是轮训所有消费者进行消息发送。这有个什么好处呢?如果你有100台机器,但是你只有10个partition其实你只有10台消费者能运转,但是在pulsar中100台机器都可以进行消费处理。
  • 键共享:类似上面说的partition维度去发送,在rocketmq中同一个key的顺序消息都会被发送到一个partition,但是这里不会有partition维度,而只是按照key的hash去分配到固定的consumer,也解决了消费者能力限制于partition个数问题。

使用

我们前面已经启动了pulsar服务,接下来我通过pulsar-client-php来使用一下

php /usr/local/bin/composer require ikilobyte/pulsar-client-php

实例化生产者

// 尝试连接到Pulsar消息队列的生产者
try {
    // 创建生产者选项实例
    $options = new ProducerOptions();
    // 设置连接超时时间为3秒
    $options->setConnectTimeout(3);
    // 设置主题为persistent类型,指定主题名为'demo'
    $options->setTopic('persistent://public/default/demo');
    // 创建生产者实例,指定Pulsar服务地址
    $producer = new Producer('pulsar://localhost:6650', $options);
    // 连接到Pulsar服务
    $producer->connect();

// 捕获连接过程中可能抛出的异常
} catch (\Exception $e) {
    // 记录异常信息到日志
    Log::error('producer connect error', [
        'message' => $e->getMessage(),
        'file'=> $e->getFile(),
        'line'=> $e->getLine(),
        'trace' => $e->getTraceAsString(),
    ]);
    // 返回表示初始化Pulsar失败的错误信息
    return ['code'=>SysException::FAILED,'msg'=>'初始化pulsar失败'];
}

发送消息

消息主体

在我们发送消息之前,我们先来了解一下消息包含哪些东西

在这里插入图片描述

在这里插入代码片

基于此,我们写一个发送消息的demo

<?php

namespace App\Console\Commands;

use App\Exceptions\SysException;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Pulsar\MessageOptions;
use Pulsar\Producer;
use Pulsar\ProducerOptions;

class PulsarTest extends Command
{
    protected $signature = 'PulsarTest';

    protected $description = 'Command description';
    public function __construct()
    {
        parent::__construct();
    }
    public function handle()
    {

        try {
            $options = new ProducerOptions();
            $options->setConnectTimeout(3);
            $options->setTopic('persistent://public/default/demo');
            $producer = new Producer('pulsar://localhost:6650', $options);
            $producer->connect();
            //发送一条普通消息
            $messageID = $producer->send(sprintf('hello %d', 11111));
            echo 'messageID ' . $messageID . "\n";
            $messageID = $producer->send(sprintf('hello properties %d', 22222), [
                //发送一条带消息属性的消息
                MessageOptions::PROPERTIES => [
                    'key' => 'value',
                    'ms' => microtime(true),
                ],
            ]);
            echo 'messageID ' . $messageID . "\n";


            //发送一条延迟消息
            $producer->send(sprintf('hello-delay %d', 33333), [
                MessageOptions::DELAY_SECONDS => 5, // Seconds
            ]);


            //批量发送消息
            $messages = [];
            for ($i = 0; $i < 10; $i++) {
                $messages[] = json_encode([
                    'id' => $i,
                    'now' => date('Y-m-d H:i:s')
                ]);
            }
            $messageID = $producer->send($messages);
            echo "batch message id ${messageID}\n";

            //关闭连接
            $producer->close();

        } catch (\Exception $e) {
            Log::error('producer connect error', [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
            ]);
            return ['code' => SysException::FAILED, 'msg' => '初始化pulsar失败'];
        }
        
    }
}

ProducerOptions

  • setTopic() -设置topic 类似于queue
  • setAuthentication() -设置连接权限认证
  • setConnectTimeout() -设置连接超时
  • setCompression() -设置压缩方式

ConsumerOptions

  • setConsumerName 设置消费者名字
  • setSubscription 设置订阅者名称
  • setSubscriptionType 设置订阅类型
  • setSubscriptionInitialPosition设置订阅初始位置
  • setNackRedeliveryDelay 设置消息重新投递延迟时间
  • setReceiveQueueSize 设置队列大小
  • setDeadLetterPolicy 设置死信策略
  • setReconnectPolicy 设置重连策略

Message

消费者拿到的消息是包含以下属性的。

 @param MessageIdData $id 消息ID数据对象
 * @param int $consumerID 消费者ID
 * @param string $publishTime 消息发布时间
 * @param string $topic 消息主题
 * @param string $payload 消息负载内容
 * @param int $batchNums 批处理消息总数,默认为1
 * @param int $batchIdx 批处理消息索引,默认为0
 * @param int $redeliveryCount 消息重试次数,默认为0
 * @param MessageCollection|null $properties 消息属性集合,可以为空

消费demo

我们先通过可视化页面看一下,我现在启动了两个生产者和三个消费者
在这里插入图片描述
我们看一下页面里面的数据信息

  • 点击storage标签看一下
    在这里插入图片描述
    由于三个消费者启动的时间不一样,所以他们读取队列的position是不一样的,他们默认读取他们启动之后的数据,这个我们可以通过option设置。
    我们现在启动一个logic_3 并指定起始位置去消费

问题

1.先启动生产者 消息丢失?关注 earliest

禁用 deleteTopicIfNoSubscriptions: 无订阅删除主题

在这里插入图片描述

持久化订阅: 如果你使用的是持久化订阅(例如 persistent://…),那么一旦订阅被创建,消费者的位置就会被跟踪。如果你希望每次启动时都从特定位置开始,可能需要考虑删除旧的订阅或创建新的订阅。
2.死信队列的使用
自动 DLQ 配置(从 Pulsar 2.8.0 开始支持)
3.share-key的使用【有问题】

4.延迟队列
精准度 秒级别

线上配置

以下是 broker.conf 文件中的一些重要配置参数及其作用:

  1. zookeeperServers

    • 说明:ZooKeeper 集群的连接字符串。
    • 示例:zookeeperServers=zk1:2181,zk2:2181,zk3:2181
  2. configurationStoreServers

    • 说明:配置存储的连接字符串。
    • 示例:configurationStoreServers=cfg1:2181,cfg2:2181,cfg3:2181
  3. brokerServicePort

    • 说明:Broker 数据服务端口。
    • 默认值:6650
    • 示例:brokerServicePort=6650
  4. webServicePort

    • 说明:用于处理 HTTP 请求的端口。
    • 默认值:8080
    • 示例:webServicePort=8080
  5. advertisedAddress

    • 说明:Broker 对外广播的地址或 IP。
    • 示例:advertisedAddress=my-broker-host
  6. maxConcurrentHttpRequests

    • 说明:最大并发 HTTP 请求数。
    • 默认值:1024
    • 示例:maxConcurrentHttpRequests=1024
  7. clusterName

    • 说明:Broker 所属集群的名称。
    • 示例:clusterName=my-cluster
  8. allowAutoTopicCreation

    • 说明:是否允许自动创建主题。
    • 默认值:true
    • 示例:allowAutoTopicCreation=true
  9. allowAutoSubscriptionCreation

    • 说明:是否允许自动创建订阅。
    • 默认值:true
    • 示例:allowAutoSubscriptionCreation=true
  10. brokerDeleteInactiveTopicsEnabled

    • 说明:是否启用删除不活跃的主题。
    • 默认值:true
    • 示例:brokerDeleteInactiveTopicsEnabled=true
  11. brokerDeleteInactiveTopicsFrequencySeconds

    • 说明:检查不活跃主题的频率(秒)。
    • 默认值:60
    • 示例:brokerDeleteInactiveTopicsFrequencySeconds=60
  12. maxUnackedMessagesPerConsumer

    • 说明:每个消费者允许的最大未确认消息数。
    • 默认值:50000
    • 示例:maxUnackedMessagesPerConsumer=50000
  13. maxMessageSize

    • 说明:消息的最大大小(字节)。
    • 默认值:5242880 (5MB)
    • 示例:maxMessageSize=5242880
  14. enablePersistentTopics

    • 说明:是否启用持久化主题。
    • 默认值:true
    • 示例:enablePersistentTopics=true
  15. enableNonPersistentTopics

    • 说明:是否启用非持久化主题。
    • 默认值:true
    • 示例:enableNonPersistentTopics=true
  16. maxProducersPerTopic

    • 说明:每个主题允许的最大生产者数。
    • 默认值:0 (无限制)
    • 示例:maxProducersPerTopic=10
  17. maxConsumersPerTopic

    • 说明:每个主题允许的最大消费者数。
    • 默认值:0 (无限制)
    • 示例:maxConsumersPerTopic=10
  18. maxSubscriptionsPerTopic

    • 说明:每个主题允许的最大订阅数。
    • 默认值:0 (无限制)
    • 示例:maxSubscriptionsPerTopic=10
  19. maxConsumersPerSubscription

    • 说明:每个订阅允许的最大消费者数。
    • 默认值:0 (无限制)
    • 示例:maxConsumersPerSubscription=10

这些参数是 Pulsar Broker 配置文件中的常见设置,用于控制 Broker 的行为、性能和安全性。根据具体需求,可以调整这些参数以优化 Broker 的运行。

pulsar部署后broker.conf一些配置项
是否自动创建
allowAutoTopicCreation=false
删除不活跃的topic
brokerDeleteInactiveTopicsEnabled=false
强制删除Namespace 开发和测试环境配置成true方便清理
forceDeleteNamespaceAllowed=false
强制删除Tenant 开发和测试环境配置成true方便清理
forceDeleteTenantAllowed=false
这个很重要,根据业务情况配,我是7= 7 * 24 * 60
topic如果存在很多订阅没有消费,那么bk存储也不会删除
解决:
1、删除订阅 下面这个
2、配置TTL
subscriptionExpirationTimeMinutes=10080

参考

下一代消息队列pulsar到底是什么
Docker部署pulsar独立集群消息队列服务器
pulsar-client-php
新一代消息中间件—Apache Pulsar
Apache Pulsar 中文文档
消息中间件Pulsar介绍

Apache Pulsar的功能特性、组件介绍、和Kafka对比

Pulsar简介及Pulsar部署、原理和使用介绍

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

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

相关文章

[代码随想录16]二叉树的重新构造,路径总和,左下角的值

前言 关于二叉树的题目&#xff0c;我认为主要是把基础的思想掌握了&#xff0c;剩下的还是拼装和组合的题目&#xff0c;我们重要的就是学会一些基本的二叉思路&#xff0c;递归好还是迭代好&#xff0c;怎么递归和怎么迭代&#xff0c;二叉树的题目在面试过程中考的是挺多的&…

数据链路层(Java)(MAC与IP的区别)

以太网协议&#xff1a; "以太⽹" 不是⼀种具体的⽹络, ⽽是⼀种技术标准; 既包含了数据链路层的内容, 也包含了⼀些物理 层的内容. 例如: 规定了⽹络拓扑结构, 访问控制⽅式, 传输速率等; 例如以太⽹中的⽹线必须使⽤双绞线; 传输速率有10M, 100M, 1000M等; 以太…

梳理你的思路(从OOP到架构设计)_基本OOP知识04

目录 1、 主动型 vs.基於被动型 API 1&#xff09;卡榫函数实现API 2&#xff09;API的分类 3&#xff09;回顾历史 4&#xff09;API >控制力 2、 结语&复习&#xff1a; 接口与类 1&#xff09;接口的表示 2&#xff09;Java的接口表示 1、 主动型 vs.基於被动…

题解 - 取数排列

题目描述 取1到N共N个连续的数字&#xff08;1≤N≤9&#xff09;&#xff0c;组成每位数不重复的所有可能的N位数&#xff0c;按从小到大的顺序进行编号。当输入一个编号M时&#xff0c;就能打印出与该编号对应的那个N位数。例如&#xff0c;当N&#xff1d;3时&#xff0c;可…

FPGA实现GTP光口数据回环传输,基于Aurora 8b/10b编解码架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 GT 高速接口解决方案 3、工程详细设计方案工程设计原理框图用户数据发送模块基于GTP高速接口的数据回环传输架构GTP IP 简介GTP 基本结构GTP 发送和接收…

【Linux】常用Linux命令大全(持续更新)

前言 汇总常用linux命令及用法&#xff0c;方便大家在日常工作中操作linux的便捷性 一、top命令 top 是一个在 Linux 系统上常用的实时系统监控工具。它提供了一个动态的、交互式的实时视图&#xff0c;显示系统的整体性能信息以及正在运行的进程的相关信息    在键入top命令…

美畅物联丨JS播放器录像功能:从技术到应用的全面解析

畅联云平台的JS播放器是一款功能十分强大的视频汇聚平台播放工具&#xff0c;它已经具备众多实用功能&#xff0c;像实时播放、历史录像回放、云台控制、倍速播放、录像记录、音频播放、画面放大、全屏展示、截图捕捉等等。这些功能构建起了一个高效、灵活且用户友好的播放环境…

SQL server学习03-创建数据表

目录 一&#xff0c;SQL server的数据类型 1&#xff0c;基本数据类型 2&#xff0c;自定义数据类型 二&#xff0c;使用T-SQL创建表 1&#xff0c;数据完整性的分类 2&#xff0c;约束的类型 3&#xff0c;创建表时创建约束 4&#xff0c;任务 5&#xff0c;由任务编写…

右玉200MW光伏电站项目 微气象、安全警卫、视频监控系统

一、项目名称 山西右玉200MW光伏电站项目 微气象、安全警卫、视频监控系统 二、项目背景&#xff1a; 山西右玉光伏发电项目位于右玉县境内&#xff0c;总装机容量为200MW&#xff0c;即太阳能电池阵列共由200个1MW多晶硅电池阵列子方阵组成&#xff0c;每个子方阵包含太阳能…

【Linux系统】—— 权限的概念

【Linux系统】—— 权限的概念 1 权限1.1 什么是权限1.2 为什么要有权限1.3 理解权限 2 文件的权限2.1 文件角色2.2 文件权限2.3 修改文件权限2.3.1 修改目标属性2.3.1.1 字符修改法2.3.1.2 8进制修改法 2.3.2 修改角色 3 文件权限补充知识点3.1 只能修改自己的文件权限3.2 没有…

重生之我在异世界学编程之C语言:深入文件操作篇(上)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 函数递归与迭代 引言正文一、为什么要用文件二、文…

ctfshow-web 151-170-文件上传

151. 我们首先想到就是上传一句话木马。但是看源代码限制了png。 &#xff08;1&#xff09;改前端代码。 这里是前端限制了上传文件类型&#xff0c;那我们就改一下就好了嘛,改成php。 这里直接修改不行&#xff0c;给大家推荐一篇简短文章&#xff0c;大家就会了&#xff08…

【Flutter_Web】Flutter编译Web第一篇(插件篇):Flutter_web实现上传TOS上传资源,编写web插件

前言 由于Flutter在双端的开发体验几乎接近的情况下&#xff0c;尝试将Flutter代码转Web端进行部署和发布&#xff0c;在其中遇到的所有问题&#xff0c;我都会通过这种方式分享出来。那么第一个要解决的就是上传资源到TOS上&#xff0c;在双端中都是通过插件的方式在各端通过…

成都银泰生物科技有限责任公司简介

成都银泰生物科技有限责任公司成立于2014年&#xff0c;是一家专注于体外诊断产品销售和服务的公司。公司位于中国四川省成都市。其所售产品涵盖了生化、免疫、POCT、凝血、输血、血球、尿液、分子诊断、病理等多个技术平台。 成都银泰生物科技有限责任公司以“科技服务人类健…

【构建工具】现代开发的重要角色

你可能有所听闻构建工具&#xff0c;但是不知道是干什么的&#xff0c;或者是开发中用到了&#xff0c;大概会使用&#xff0c;但是想理解一下具体的工作原理等&#xff0c;那么我将分享一下我对其的理解。【 我将分为两篇来讲解】。 当我们谈到构建工具时&#xff0c;可以把它…

Spring 面试题整理

文章目录 一、控制反转 IoC什么是 Bean 和 Spring Bean&#xff1f;依赖注入的常见方式&#xff1f;Bean 的作用域有哪些&#xff1f;protype bean 里面的依赖是 singleton bean 的话&#xff0c;IoC 容器会怎么处理&#xff1f;Bean 的生命周期&#xff1f;Resource 和 Autowi…

Visual Studio 2022+CMake配置PCL1.14.1

前言 本教程只是提供高效的PCL配置流程&#xff0c;不提供Qt环境配置&#xff0c;如果需要GUI界面&#xff0c;则需要自寻查找Cmake配置QT的教程。请相信&#xff0c;在CMake之下没有任何事是困难的&#xff0c;最困难的工作已经由前辈们完成。因此&#xff0c;对于C用户来说学…

可视化数据

数据科学家会直观呈现数据&#xff0c;以更好地理解数据。 他们可以扫描原始数据、检查摘要度量值&#xff08;如平均值&#xff09;或绘制数据图表。 图表是一种可视化数据的强有力方式&#xff0c;数据科学家经常使用图表快速了解适度复杂的模式。 直观地表示数据 绘制图表…

【Linux网络编程】传输协议UDP

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 &#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系…

SEC_ASA 第二天作业

拓扑 按照拓扑图配置 NTP&#xff0c;Server端为 Outside路由器&#xff0c;Client端为 ASA&#xff0c;两个设备的 NTP传输使用MD5做校验。&#xff08;安全 V4 LAB考点&#xff09; 提示&#xff1a;Outside路由器作为 Server端要配置好正确的时间和时区&#xff0c;ASA防…