40分钟学 Go 语言高并发:并发下载器开发实战教程

并发下载器开发实战教程

一、系统设计概述

1.1 功能需求表

功能模块描述技术要点
分片下载将大文件分成多个小块并发下载goroutine池、分片算法
断点续传支持下载中断后继续下载文件指针定位、临时文件管理
进度显示实时显示下载进度和速度进度计算、速度统计
错误处理处理下载过程中的各种错误错误类型定义、重试机制
文件合并将下载的分片合并成完整文件文件操作、数据校验

1.2 核心结构设计

// 下载任务结构
type DownloadTask struct {
    URL           string
    TargetPath    string
    TotalSize     int64
    ChunkSize     int64
    Chunks        []*Chunk
    Progress      *Progress
    ErrorHandler  *ErrorHandler
    Concurrency   int
    RetryTimes    int
    RetryInterval time.Duration
}

// 分片信息
type Chunk struct {
    ID           int
    Start        int64
    End          int64
    Downloaded   int64
    Status       ChunkStatus
    TempFilePath string
}

// 进度信息
type Progress struct {
    TotalSize     int64
    Downloaded    int64
    Speed         float64
    Percentage    float64
    LastUpdate    time.Time
    StatusChannel chan StatusUpdate
}

// 错误处理器
type ErrorHandler struct {
    RetryTimes    int
    RetryInterval time.Duration
    Errors        chan error
    ErrorLog      *log.Logger
}

二、核心代码实现

2.1 主程序入口

package main

import (
    "fmt"
    "log"
    "os"
    "time"
)

func main() {
    // 创建下载任务
    task := &DownloadTask{
        URL:           "https://example.com/largefile.zip",
        TargetPath:    "largefile.zip",
        Concurrency:   5,
        RetryTimes:    3,
        RetryInterval: time.Second * 5,
    }

    // 初始化下载器
    downloader := NewDownloader(task)

    // 开始下载
    err := downloader.Start()
    if err != nil {
        log.Fatal(err)
    }
}

// NewDownloader 创建新的下载器实例
func NewDownloader(task *DownloadTask) *Downloader {
    return &Downloader{
        task:    task,
        progress: NewProgress(),
        errorHandler: NewErrorHandler(task.RetryTimes, task.RetryInterval),
    }
}

2.2 分片下载实现

// 分片管理
func (d *Downloader) splitTask() error {
    // 获取文件大小
    totalSize, err := d.getFileSize()
    if err != nil {
        return err
    }
    d.task.TotalSize = totalSize

    // 计算分片大小
    chunkSize := d.calculateChunkSize(totalSize)
    d.task.ChunkSize = chunkSize

    // 创建分片
    var chunks []*Chunk
    for i := 0; i < d.calculateChunkCount(); i++ {
        start := int64(i) * chunkSize
        end := start + chunkSize - 1
        if i == d.calculateChunkCount()-1 {
            end = totalSize - 1
        }

        chunk := &Chunk{
            ID:    i,
            Start: start,
            End:   end,
            Status: ChunkStatusPending,
            TempFilePath: fmt.Sprintf("%s.part%d", d.task.TargetPath, i),
        }
        chunks = append(chunks, chunk)
    }
    d.task.Chunks = chunks
    return nil
}

// 下载单个分片
func (d *Downloader) downloadChunk(chunk *Chunk) error {
    client := &http.Client{}
    req, err := http.NewRequest("GET", d.task.URL, nil)
    if err != nil {
        return err
    }

    // 设置Range头部
    req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", chunk.Start, chunk.End))

    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // 创建临时文件
    tmpFile, err := os.Create(chunk.TempFilePath)
    if err != nil {
        return err
    }
    defer tmpFile.Close()

    // 写入数据并更新进度
    buffer := make([]byte, 32*1024)
    for {
        n, err := resp.Body.Read(buffer)
        if n > 0 {
            tmpFile.Write(buffer[:n])
            chunk.Downloaded += int64(n)
            d.updateProgress(int64(n))
        }
        if err != nil {
            if err == io.EOF {
                break
            }
            return err
        }
    }

    chunk.Status = ChunkStatusCompleted
    return nil
}

2.3 进度监控实现

// 进度管理器
type Progress struct {
    mu            sync.Mutex
    downloaded    int64
    totalSize     int64
    startTime     time.Time
    lastUpdate    time.Time
    speedSamples  []float64
    statusChannel chan StatusUpdate
}

// 更新进度
func (p *Progress) Update(n int64) {
    p.mu.Lock()
    defer p.mu.Unlock()

    p.downloaded += n
    now := time.Now()
    duration := now.Sub(p.lastUpdate).Seconds()
    
    if duration >= 1.0 {
        speed := float64(n) / duration
        p.speedSamples = append(p.speedSamples, speed)
        if len(p.speedSamples) > 10 {
            p.speedSamples = p.speedSamples[1:]
        }
        p.lastUpdate = now
        
        // 计算平均速度
        var avgSpeed float64
        for _, s := range p.speedSamples {
            avgSpeed += s
        }
        avgSpeed /= float64(len(p.speedSamples))

        // 发送状态更新
        p.statusChannel <- StatusUpdate{
            Downloaded: p.downloaded,
            TotalSize: p.totalSize,
            Speed: avgSpeed,
            Percentage: float64(p.downloaded) / float64(p.totalSize) * 100,
        }
    }
}

// 显示进度
func (p *Progress) displayProgress() {
    for status := range p.statusChannel {
        fmt.Printf("\rProgress: %.2f%% Speed: %.2f MB/s", 
            status.Percentage,
            status.Speed/1024/1024)
    }
}

2.4 错误处理实现

// 错误处理器
type ErrorHandler struct {
    retryTimes    int
    retryInterval time.Duration
    errors        chan error
    errorLog      *log.Logger
}

// 错误重试
func (eh *ErrorHandler) RetryDownload(chunk *Chunk, downloadFunc func(*Chunk) error) error {
    var lastErr error
    for i := 0; i < eh.retryTimes; i++ {
        err := downloadFunc(chunk)
        if err == nil {
            return nil
        }
        lastErr = err
        eh.logError(fmt.Sprintf("Chunk %d download failed: %v, retry %d/%d", 
            chunk.ID, err, i+1, eh.retryTimes))
        time.Sleep(eh.retryInterval)
    }
    return fmt.Errorf("max retry times reached: %v", lastErr)
}

// 错误日志记录
func (eh *ErrorHandler) logError(msg string) {
    eh.errorLog.Println(msg)
}

2.5 完整下载管理器

// Downloader 主程序流程
func (d *Downloader) Start() error {
    // 1. 切分任务
    if err := d.splitTask(); err != nil {
        return err
    }

    // 2. 创建工作池
    workPool := make(chan *Chunk, d.task.Concurrency)
    var wg sync.WaitGroup

    // 3. 启动工作协程
    for i := 0; i < d.task.Concurrency; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for chunk := range workPool {
                err := d.errorHandler.RetryDownload(chunk, d.downloadChunk)
                if err != nil {
                    d.errorHandler.errors <- err
                }
            }
        }()
    }

    // 4. 分发任务
    go func() {
        for _, chunk := range d.task.Chunks {
            workPool <- chunk
        }
        close(workPool)
    }()

    // 5. 启动进度显示
    go d.progress.displayProgress()

    // 6. 等待所有下载完成
    wg.Wait()

    // 7. 合并文件
    return d.mergeChunks()
}

// 合并分片文件
func (d *Downloader) mergeChunks() error {
    targetFile, err := os.Create(d.task.TargetPath)
    if err != nil {
        return err
    }
    defer targetFile.Close()

    for _, chunk := range d.task.Chunks {
        chunkFile, err := os.Open(chunk.TempFilePath)
        if err != nil {
            return err
        }

        _, err = io.Copy(targetFile, chunkFile)
        chunkFile.Close()
        os.Remove(chunk.TempFilePath)
        
        if err != nil {
            return err
        }
    }

    return nil
}

三、系统流程图

添加一个流程图来说明下载器的工作流程:
在这里插入图片描述
让我们再添加一个并发控制的状态图:
在这里插入图片描述

这个并发下载器的实现包含了以下核心特点:

  1. 分片下载设计

    • 根据文件大小自动计算合适的分片大小
    • 支持断点续传
    • 临时文件管理
    • 分片合并校验
  2. goroutine协作

    • 使用工作池控制并发数
    • 协程间通信采用channel
    • 优雅的协程退出机制
    • 资源释放保证
  3. 进度监控

    • 实时速度计算
    • 平均速度统计
    • 进度百分比显示
    • 状态更新通知

好的,让我继续完成错误处理部分和补充其他重要内容:

  1. 错误处理
    • 完整的重试机制
    • 错误日志记录
    • 错误类型分类
    • 优雅降级策略

接下来补充一些重要的实现代码:

package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "sync"
    "time"
)

// 错误类型定义
type DownloadError struct {
    ChunkID int
    Err     error
    Retried int
}

func (e *DownloadError) Error() string {
    return fmt.Sprintf("chunk %d download failed: %v (retried: %d times)", 
        e.ChunkID, e.Err, e.Retried)
}

// 状态更新结构
type StatusUpdate struct {
    ChunkID    int
    Downloaded int64
    Speed      float64
    Error      error
}

// 下载管理器
type Downloader struct {
    ctx          context.Context
    cancel       context.CancelFunc
    task         *DownloadTask
    progress     *Progress
    errorHandler *ErrorHandler
    wg           sync.WaitGroup
}

// 创建新的下载管理器
func NewDownloader(task *DownloadTask) *Downloader {
    ctx, cancel := context.WithCancel(context.Background())
    return &Downloader{
        ctx:          ctx,
        cancel:       cancel,
        task:         task,
        progress:     NewProgress(task.TotalSize),
        errorHandler: NewErrorHandler(task.RetryTimes, task.RetryInterval),
    }
}

// 下载器核心实现
func (d *Downloader) Start() error {
    // 1. 准备工作
    if err := d.prepare(); err != nil {
        return fmt.Errorf("preparation failed: %v", err)
    }

    // 2. 创建工作池
    workChan := make(chan *Chunk, d.task.Concurrency)
    statusChan := make(chan StatusUpdate, d.task.Concurrency)

    // 3. 启动工作协程
    for i := 0; i < d.task.Concurrency; i++ {
        d.wg.Add(1)
        go d.worker(workChan, statusChan)
    }

    // 4. 启动状态监控
    go d.monitorStatus(statusChan)

    // 5. 分发任务
    for _, chunk := range d.task.Chunks {
        select {
        case workChan <- chunk:
        case <-d.ctx.Done():
            return fmt.Errorf("download cancelled")
        }
    }

    // 6. 关闭工作通道
    close(workChan)

    // 7. 等待所有工作完成
    d.wg.Wait()

    // 8. 检查是否有错误发生
    if err := d.errorHandler.GetFatalError(); err != nil {
        return err
    }

    // 9. 合并文件
    return d.mergeChunks()
}

// 工作协程
func (d *Downloader) worker(workChan <-chan *Chunk, statusChan chan<- StatusUpdate) {
    defer d.wg.Done()

    for chunk := range workChan {
        err := d.downloadChunkWithRetry(chunk)
        if err != nil {
            statusChan <- StatusUpdate{
                ChunkID: chunk.ID,
                Error:   err,
            }
            continue
        }

        statusChan <- StatusUpdate{
            ChunkID:    chunk.ID,
            Downloaded: chunk.End - chunk.Start + 1,
        }
    }
}

// 带重试的分片下载
func (d *Downloader) downloadChunkWithRetry(chunk *Chunk) error {
    retries := 0
    for retries <= d.task.RetryTimes {
        err := d.downloadChunk(chunk)
        if err == nil {
            return nil
        }

        retries++
        if retries > d.task.RetryTimes {
            return &DownloadError{
                ChunkID: chunk.ID,
                Err:     err,
                Retried: retries - 1,
            }
        }

        // 记录重试日志
        log.Printf("Chunk %d download failed: %v, retrying (%d/%d)...", 
            chunk.ID, err, retries, d.task.RetryTimes)
        
        // 等待重试间隔
        select {
        case <-time.After(d.task.RetryInterval):
        case <-d.ctx.Done():
            return fmt.Errorf("download cancelled during retry")
        }
    }
    return nil
}

// 优化的分片下载实现
func (d *Downloader) downloadChunk(chunk *Chunk) error {
    // 创建HTTP请求
    req, err := http.NewRequestWithContext(d.ctx, "GET", d.task.URL, nil)
    if err != nil {
        return err
    }

    // 设置Range头
    req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", chunk.Start+chunk.Downloaded, chunk.End))

    // 发送请求
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // 检查响应状态
    if resp.StatusCode != http.StatusPartialContent {
        return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
    }

    // 打开或创建临时文件
    f, err := os.OpenFile(chunk.TempFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        return err
    }
    defer f.Close()

    // 设置写入位置
    if _, err := f.Seek(chunk.Downloaded, io.SeekStart); err != nil {
        return err
    }

    // 创建带缓冲的写入器
    bufWriter := bufio.NewWriter(f)
    defer bufWriter.Flush()

    // 下载数据
    buffer := make([]byte, 32*1024)
    for {
        select {
        case <-d.ctx.Done():
            return fmt.Errorf("download cancelled")
        default:
            n, err := resp.Body.Read(buffer)
            if n > 0 {
                // 写入数据
                if _, err := bufWriter.Write(buffer[:n]); err != nil {
                    return err
                }
                
                // 更新进度
                chunk.Downloaded += int64(n)
                d.progress.Update(int64(n))
            }
            if err == io.EOF {
                return nil
            }
            if err != nil {
                return err
            }
        }
    }
}

// 状态监控
func (d *Downloader) monitorStatus(statusChan <-chan StatusUpdate) {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()

    for {
        select {
        case status := <-statusChan:
            if status.Error != nil {
                d.errorHandler.HandleError(status.Error)
                continue
            }
            d.progress.Update(status.Downloaded)

        case <-ticker.C:
            d.displayProgress()

        case <-d.ctx.Done():
            return
        }
    }
}

// 显示下载进度
func (d *Downloader) displayProgress() {
    status := d.progress.GetStatus()
    fmt.Printf("\rProgress: %.2f%% Speed: %.2f MB/s", 
        status.Percentage,
        status.Speed/1024/1024)
}

// 优化的文件合并实现
func (d *Downloader) mergeChunks() error {
    // 创建目标文件
    targetFile, err := os.Create(d.task.TargetPath)
    if err != nil {
        return err
    }
    defer targetFile.Close()

    // 使用bufio提升写入性能
    bufWriter := bufio.NewWriter(targetFile)
    defer bufWriter.Flush()

    // 合并所有分片
    for _, chunk := range d.task.Chunks {
        // 打开分片文件
        chunkFile, err := os.Open(chunk.TempFilePath)
        if err != nil {
            return err
        }

        // 使用bufio提升读取性能
        bufReader := bufio.NewReader(chunkFile)

        // 复制数据
        _, err = io.Copy(bufWriter, bufReader)
        chunkFile.Close()
        
        // 删除临时文件
        os.Remove(chunk.TempFilePath)

        if err != nil {
            return fmt.Errorf("failed to merge chunk %d: %v", chunk.ID, err)
        }
    }

    return nil
}

func main() {
    // 创建下载任务
    task := &DownloadTask{
        URL:           "https://example.com/largefile.zip",
        TargetPath:    "largefile.zip",
        Concurrency:   5,
        RetryTimes:    3,
        RetryInterval: time.Second * 5,
        ChunkSize:     1024 * 1024 * 10, // 10MB per chunk
    }

    // 创建下载器
    downloader := NewDownloader(task)

    // 开始下载
    if err := downloader.Start(); err != nil {
        log.Fatal(err)
    }

    fmt.Println("\nDownload completed successfully!")
}

并发下载器的性能优化建议表:

优化方向具体措施预期效果
并发控制根据系统资源调整并发数避免资源竞争,提高整体性能
内存使用使用固定大小的缓冲区减少内存分配,避免GC压力
IO操作使用bufio进行缓冲IO减少系统调用,提高IO效率
错误处理实现智能重试机制提高下载成功率
进度计算批量更新进度减少锁竞争,提高并发效率

核心优化要点:

  1. 分片策略优化

    • 动态调整分片大小
    • 考虑网络状况
    • 考虑文件大小
    • 优化分片合并
  2. 内存管理优化

    • 使用对象池
    • 控制缓冲区大小
    • 及时释放资源
    • 避免内存泄漏
  3. 并发控制优化

    • 动态调整goroutine数量
    • 使用环形缓冲区
    • 实现背压机制
    • 优化锁策略
  4. IO性能优化

    • 使用bufio
    • 适当的buffer大小
    • 批量写入
    • 减少系统调用

使用建议:

  1. 根据实际需求调整参数

    • 并发数
    • 分片大小
    • 缓冲区大小
    • 重试策略
  2. 监控关键指标

    • CPU使用率
    • 内存占用
    • 磁盘IO
    • 网络带宽
  3. 做好错误处理

    • 完整的日志记录
    • 合理的重试策略
    • 优雅的降级处理
    • 用户友好的错误提示
  4. 进行充分测试

    • 单元测试
    • 性能测试
    • 压力测试
    • 异常场景测试

这个并发下载器的实现考虑了实际应用中的各种场景,包括:

  1. 网络不稳定
  2. 断点续传需求
  3. 大文件处理
  4. 资源限制
  5. 错误恢复
  6. 性能优化

通过这些特性和优化,可以实现一个稳定高效的文件下载器。


怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

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

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

相关文章

李宏毅机器学习课程知识点摘要(1-5集)

前5集 过拟合&#xff1a; 参数太多&#xff0c;导致把数据集刻画的太完整。而一旦测试集和数据集的关联不大&#xff0c;那么预测效果还不如模糊一点的模型 所以找的数据集的量以及准确性也会影响 由于线性函数的拟合一般般&#xff0c;所以用一组函数去分段来拟合 sigmoi…

Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序

在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序 IntelliJ IDEA 是一个用 Java 编写的集成开发环境 (IDE)。它用于开发计算机软件。此 IDE 由 Jetbrains 开发&#xff0c;提供 Apache 2 许可社区版和商业版。它是一种智能的上下文感知 IDE&#xff0c;可用于在各种应用程序…

本地Docker部署开源WAF雷池并实现异地远程登录管理界面

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

如何快速将Excel数据导入到SQL Server数据库

工作中&#xff0c;我们经常需要将Excel数据导入到数据库&#xff0c;但是对于数据库小白来说&#xff0c;这可能并非易事&#xff1b;对于数据库专家来说&#xff0c;这又可能非常繁琐。 这篇文章将介绍如何帮助您快速的将Excel数据导入到sql server数据库。 准备工作 这里&…

[产品管理-91]:产品经理的企业运营的全局思维-1

目录 前言&#xff1a;企业架构图 产品经理的企业运营全局思维 1、用户 - 用户价值与体验&#xff1a;真正的需求&#xff0c;真正的问题&#xff0c;一切的原点 2、大势 - 顺应宏观大势&#xff1a;政策趋势、行业趋势、技术趋势 3、市场 - 知己知彼&#xff1a;市场调研…

简单实现vue2响应式原理

vue2 在实现响应式时&#xff0c;是根据 object.defineProperty() 这个实现的&#xff0c;vue3 是通过 Proxy 对象实现&#xff0c;但是实现思路是差不多的&#xff0c;响应式其实就是让 函数和数据产生关联&#xff0c;在我们对数据进行修改的时候&#xff0c;可以执行相关的副…

论文解析:EdgeToll:基于区块链的异构公共共享收费系统(2019,IEEE INFOCOM 会议);layer2 应对:频繁小额交易,无交易费

目录 论文解析:EdgeToll:基于区块链的异构公共共享收费系统(2019,IEEE INFOCOM 会议) 核心内容概述 核心创新点原理与理论 layer2 应对:频繁小额交易,无交易费 论文解析:EdgeToll:基于区块链的异构公共共享收费系统(2019,IEEE INFOCOM 会议) 核心内容是介绍了一个…

基于python Django的boss直聘数据采集与分析预测系统,爬虫可以在线采集,实时动态显示爬取数据,预测基于技能匹配的预测模型

本系统是基于Python Django框架构建的“Boss直聘”数据采集与分析预测系统&#xff0c;旨在通过技能匹配的方式对招聘信息进行分析与预测&#xff0c;帮助求职者根据自身技能找到最合适的职位&#xff0c;同时为招聘方提供更精准的候选人推荐。系统的核心预测模型基于职位需求技…

SemiDrive E3 硬件设计系列---唤醒电路设计

一、前言 E3 系列芯片是芯驰半导体高功能安全的车规级 MCU&#xff0c;对于 MCU 的硬件设计部分&#xff0c;本系列将会分模块进行讲解&#xff0c;旨在介绍 E3 系列芯片在硬件设计方面的注意事项与经验&#xff0c;本文主要讲解 E3 硬件设计中唤醒电路部分的设计。 二、RTC 模…

Leetcode198. 打家劫舍(HOT100)

代码&#xff1a; class Solution { public:int rob(vector<int>& nums) {int n nums.size();vector<int> f(n 1), g(n 1);for (int i 1; i < n; i) {f[i] g[i - 1] nums[i - 1];g[i] max(f[i - 1], g[i - 1]);}return max(f[n], g[n]);} }; 这种求…

一文探究48V新型电气架构下的汽车连接器

【哔哥哔特导读】汽车电源架构不断升级趋势下&#xff0c;48V系统是否还有升级的必要&#xff1f;48V新型电气架构将给连接器带来什么改变&#xff1f; 在插混和纯电车型逐渐普及、800V高压平台持续升级的当下&#xff0c;48V技术还有市场吗? 这个问题很多企业的回答是不一定…

React学习05 - redux

文章目录 redux工作流程redux理解redux理解及三个核心概念redux核心apiredux异步编程react-redux组件间数据共享 纯函数redux调试工具项目打包 redux工作流程 redux理解 redux是一个专门用于状态管理的JS库&#xff0c;可以用在react, angular, vue 等项目中。在与react配合使…

2024年11月最新 Alfred 5 Powerpack (MACOS)下载

在现代数字化办公中&#xff0c;我们常常被繁杂的任务所包围&#xff0c;而时间的高效利用成为一项核心需求。Alfred 5 Powerpack 是一款专为 macOS 用户打造的高效工作流工具&#xff0c;以其强大的定制化功能和流畅的用户体验&#xff0c;成为众多效率爱好者的首选。 点击链…

batchnorm与layernorn的区别

1 原理 简单总结&#xff1a; batchnorn 和layernorm是在不同维度上对特征进行归一化处理。 batchnorm在batch这一维度上&#xff0c; 对一个batch内部所有样本&#xff0c; 在同一个特征通道上进行归一化。 举个例子&#xff0c; 假设输入的特征图尺寸为16x224x224x256&…

【c++丨STL】stack和queue的使用及模拟实现

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 前言 一、什么是容器适配器 二、stack的使用及模拟实现 1. stack的使用 empty size top push和pop swap 2. stack的模拟实现 三、queue的…

ApiChain 从迭代到项目 接口调试到文档生成单元测试一体化工具

项目地址&#xff1a;ApiChain 项目主页 ApiChain 简介 ApiChain 是一款类似 PostMan 的接口网络请求与文档生成软件&#xff0c;与 PostMan 不同的是&#xff0c;它基于 项目和迭代两个视角管理我们的接口文档&#xff0c;前端和测试更关注版本迭代中发生变更的接口编写代码…

力扣面试题 - 24 插入

题目&#xff1a; 给定两个整型数字 N 与 M&#xff0c;以及表示比特位置的 i 与 j&#xff08;i < j&#xff0c;且从 0 位开始计算&#xff09;。 编写一种方法&#xff0c;使 M 对应的二进制数字插入 N 对应的二进制数字的第 i ~ j 位区域&#xff0c;不足之处用 0 补齐…

网络安全,文明上网(4)掌握网络安全技术

前言 在数字化时代&#xff0c;个人信息和企业数据的安全变得尤为重要。为了有效保护这些宝贵资产&#xff0c;掌握一系列网络安全技术是关键。 核心技术及实施方式 1. 网络监控与过滤系统&#xff1a; 这些系统构成了网络防御体系的基石&#xff0c;它们负责监控网络通信&…

[开源] SafeLine 好用的Web 应用防火墙(WAF)

SafeLine&#xff0c;中文名 “雷池”&#xff0c;是一款简单好用, 效果突出的 Web 应用防火墙(WAF)&#xff0c;可以保护 Web 服务不受黑客攻击 一、简介 雷池通过过滤和监控 Web 应用与互联网之间的 HTTP 流量来保护 Web 服务。可以保护 Web 服务免受 SQL 注入、XSS、 代码注…

ELK8.15.4搭建开启安全认证

安装 Elastic &#xff1a;Elasticsearch&#xff0c;Kibana&#xff0c;Logstash 另外安装一个收集器filebeat 通过二进制安装包进行安装 创建一个专门放elk目录 mkdir /elk/ mkdir /elk/soft下载 es 、kibana、Logstash、filebeat二进制包 cd /elk/softwget https://art…