当前位置: 首页 > article >正文

【Node.js 】在Windows 下搭建适配 DPlayer 的轻量(简陋)级弹幕后端服务

一、引言

DPlayer官网:DPlayer

官方弹幕后端服务:DPlayer-node

MoePlayer/DPlayer-node:使用 Docker for DPlayer Node.js 后端(https://github.com/DIYgod/DPlayer)

本来想直接使用官网提供的DPlayer-node直接搭建的,折腾了一天,在Windows上又是装Docker,又是Redis,又是Mongodb,可能是我的环境或者Windows的原因,启动就报错,遂自己做一个简单的弹幕后端服务。

当然,为了让DPlayer能够成功接收自己做的接口,还要看一下DPlayer 的官方文档与DPlayer-node的源码,返回DPplayer能够接受的接口数据。

二、环境

系统:Windowsjs

数据库:Mysql

后端:Node.js

IDE:Vscode

接口测试:postman(可选)

 三、核心逻辑

1.视频开始前查询弹幕

  • 客户端请求:当用户打开一个视频时,前端(如 DPlayer)会向弹幕服务器发送一个请求,获取与该视频相关的所有弹幕信息。请求中通常会包含视频的唯一标识(如 videoId)。
  • 服务器查询:弹幕服务器接收到请求后,会根据视频 ID 从数据库中查询所有相关的弹幕数据。查询结果包括弹幕的文本内容和出现时间(time)等信息。
  • 返回弹幕数据:服务器将查询到的弹幕数据返回给客户端,客户端接收到数据后将其存储在内存中。


2.视频播放过程中的弹幕显示

  • DPlayer 处理弹幕:在视频播放过程中,DPlayer 会根据每个弹幕的出现时间(time)来控制弹幕的显示。当视频播放时间达到某个弹幕的 time 值时,DPlayer 会在屏幕上显示该弹幕。
  • 弹幕的实时显示:DPlayer 会持续监测视频的播放时间,并在合适的时间点显示对应的弹幕,从而实现弹幕的实时滚动效果。


3.添加新弹幕

  • 客户端发送请求:当用户发送一条新的弹幕时,前端会向弹幕服务器发送一个 POST 请求,请求体中包含弹幕的文本内容、出现时间、颜色、类型等信息。
  • 服务器处理请求:弹幕服务器接收到请求后,会将新的弹幕信息存储到数据库中。
  • 更新弹幕数据:新的弹幕数据会被添加到数据库中,以便其他客户端在请求弹幕数据时能够获取到最新的弹幕信息。


4.系统架构图

+-------------------+          +-------------------+          +-------------------+
|                   |          |                   |          |                   |
|  客户端 (DPlayer) |   HTTP   |  弹幕服务器       |   SQL    |  数据库 (MySQL)   |
|                   | <-------> |                   | <-------> |                   |
|  - 视频播放       |          |  - 处理请求       |          | -  存储弹幕数据   |
|  - 显示弹幕       |          |  - 返回弹幕数据   |          |  - 查询弹幕数据   |
|                   |          |                   |          |                   |
+-------------------+          +-------------------+          +-------------------+

四、数据库&接口分析

1.网络请求分析

直接在Vscode新建一个HTML文件,引入DPlayer:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>视频弹幕演示</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.css">
</head><body><div id="dplayer"></div><script src="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js"></script><script>const videoId = 'test'; // ❗ 替换为实际视频 ID(如 1028,需与后端一致)const dp = new DPlayer({container: document.getElementById('dplayer'),video: {url: 'video/test.mp4', // 视频路径type: 'mp4',name: '演示视频'},danmaku: {id: videoId, // 必须与后端路由中的 :id 一致api: 'http://127.0.0.1:3000/danmaku/', // 后端弹幕服务根路径addition: [// 外挂弹幕//`http://127.0.0.1:3000/danmaku/list/${videoId}` ]}});// 监听 DPlayer 的弹幕发送事件dp.on('danmaku_send', (danmaku) => {console.log('发送请求')console.log('视频ID:' + videoId)});</script>
</body></html>

视频路径改为本地的视频,里面的api和addition就随便写一个接口,不管能不能请求成功,重点是看DPlayer请求的接口;

  • 在Vscode中安装Live Server

  • 在新建的HTML页面上按快捷键:Alt+L+O,自动打开浏览器,然后按F12打开开发者工具:

  • 按F5或点击刷新按钮刷新本页面,筛选Fetch/XHR,这个就是发送的请求

可以看到这个请求是404,没有请求到数据,因为我还没建这个网络请求

点击会显示请求信息:

http://127.0.0.1:3000/danmaku/v3/?id=test

我写的请求明明是:“api: 'http://127.0.0.1:3000/danmaku/'”

但浏览器发出的请求是在我写的基础上增加了“v3/?id=test”,说明这个接口被DPlayer.min.js修改了,所以我需要专门提供这个接口;

  • 增加弹幕

随便发送一个弹幕,浏览器会捕获到发送弹幕的请求

http://127.0.0.1:3000/danmaku/v3/

和第一个接口相比没有了参数?id,所以我要为这个接口提供get还有post请求,get请求根据id返回数据,post请求插入数据。

  • 切换到负载

这里可以看到请求所需的数据:

{"id": "test","author": "DIYgod","time": 21.778242,"text": "dsfsd","color": 16777215,"type": 0
}

这就是数据表所需的数据。

    2.源码分析

    根据官方提供的后端服务推测所需的数据表结构和接口

    DPlayer-node/routes at master · MoePlayer/DPlayer-node

    查看根目录下的路由文件:

    DPlayer-node/router.js

    const Router = require('koa-router');
    const router = new Router();router.get('/v3', require('./routes/get'));
    router.post('/v3', require('./routes/post'));
    router.get('/v3/bilibili', require('./routes/bilibili'));module.exports = router;

    该服务一共接收三个请求:post、get、bilibili,关联至DPlayer-node/routes/目录下的三个js文件:

    bilibili.js

    set cache time

    7 years ago

    get.js

    compatible with empty author

    7 years ago

    post.js

    fix redis del

    7 years ago

    bilibili.js顾名思义是B站的弹幕接口,不知现在还有没有用,这里也不需要用到B站的弹幕,故跳过;

    主要重点是负责get/post请求的这两个js文件,觉得麻烦直接问AI一步到位。

    post.js

    const logger = require('../utils/logger');module.exports = async (ctx) => {const body = ctx.request.body;const dan = new ctx.mongodb({player: body.id,author: body.author,time: body.time,text: body.text,color: body.color,type: body.type,ip: ctx.ips[0] || ctx.ip,referer: ctx.headers.referer,date: +new Date(),});try {const data = await dan.save();ctx.body = JSON.stringify({code: 0,data,});ctx.redis.del(`danmaku${data.player}`);}catch (err) {logger.error(err);ctx.body = JSON.stringify({code: 1,msg: `Database error: ${err}`,});}
    };
    1. 接收前端发送的弹幕数据。

    2. 将弹幕数据保存到数据库中。

    3. 如果保存成功,删除对应的 Redis 缓存并返回成功响应。

    4. 如果保存失败,记录错误日志并返回错误响应。

    get.js

    function htmlEncode (str) {return str ? str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g, '&#x2f;') : '';
    }module.exports = async (ctx) => {const { id, limit } = ctx.request.query;let data = await ctx.redis.get(`danmaku${id}`);if (data) {data = JSON.parse(data);if (limit) {data = data.slice(-1 * parseInt(limit));}ctx.response.set('X-Koa-Redis', 'true');} else {data = await ctx.mongodb.find({ player: id }) || [];ctx.redis.set(`danmaku${id}`, JSON.stringify(data));if (limit) {data = data.slice(-1 * parseInt(limit));}ctx.response.set('X-Koa-Mongodb', 'true');}ctx.body = JSON.stringify({code: 0,data: data.map((item) => [item.time || 0, item.type || 0, item.color || 16777215, htmlEncode(item.author) || 'DPlayer', htmlEncode(item.text) || '']),});
    };
    1. 接收前端发送的视频 ID 和弹幕数量限制参数。

    2. 尝试从 Redis 缓存中获取弹幕数据,如果缓存存在则直接返回。

    3. 如果缓存不存在,从 MongoDB 数据库中查询弹幕数据,并将结果存入 Redis 缓存。

    4. 根据 limit 参数对数据进行截取,只返回最近的弹幕数据。

    5. 对弹幕的作者和文本内容进行 HTML 编码,防止 XSS 攻击。

    6. 返回格式化后的弹幕数据给客户端。

    五、分析结果

    1.数据库表结构

    表:danmaku(弹幕表)

    字段名类型描述
    idINT PRIMARY KEY弹幕唯一标识
    playerVARCHAR(255)关联的视频唯一标识
    authorVARCHAR(255)弹幕作者
    timeDECIMAL(10, 2)弹幕出现的时间(秒)
    textTEXT弹幕文本内容
    colorVARCHAR(7)弹幕颜色(十六进制)
    typeINT弹幕类型(如滚动、顶部、底部)
    ipVARCHAR(45)发送弹幕的用户IP地址
    refererTEXT请求来源页面
    dateTIMESTAMP弹幕发送的时间戳

    2.接口格式

    2.1获取弹幕

    • 接口地址GET /v3

    • 请求参数

      • videoId:视频唯一标识

      • limit:限制返回的弹幕数量(可选)

    • 响应格式

      {"code": 0,"data": [[10.5,           // 弹幕出现的时间(秒)1,              // 弹幕类型16777215,       // 弹幕颜色(十六进制转十进制)"DPlayer",      // 弹幕作者(HTML编码)"这是一条测试弹幕" // 弹幕文本内容(HTML编码)]]
      }

    2.2添加弹幕

    • 接口地址POST /v3

    • 请求体

      {"id": "test",       // 视频唯一标识"author": "user1",  // 弹幕作者"time": 20.0,       // 弹幕出现的时间(秒)"text": "这是一条新弹幕", // 弹幕文本内容"color": "#FFFFFF", // 弹幕颜色(十六进制)"type": 1           // 弹幕类型
      }
    • 响应格式

      {"code": 0,"data": {"id": 2,"player": "test","author": "user1","time": 20.0,"text": "这是一条新弹幕","color": "#FFFFFF","type": 1,"ip": "192.168.1.1","referer": "http://example.com","date": 1714234800000}
      }

    六、创建数据表

    -- 创建数据库
    CREATE DATABASE danmaku_db;-- 使用创建的数据库
    USE danmaku_db;-- 创建弹幕表
    CREATE TABLE danmaku (id INT PRIMARY KEY AUTO_INCREMENT,player VARCHAR(255) NOT NULL,author VARCHAR(255) NOT NULL,time DECIMAL(10, 2) NOT NULL,text TEXT NOT NULL,color VARCHAR(20) NOT NULL,type INT NOT NULL,ip VARCHAR(45) NOT NULL,referer TEXT,date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    七、编写接口

    1. 环境验证

    以下需要Node环境,cmd输入以下命令检查是否含有所需环境:

    node -v
    npm -v

    返回版本号证明安装成功。

    2. 创建项目

    mkdir danmaku-server
    cd danmaku-server
    npm init -y

    3. 安装依赖

    npm install express mysql2 body-parser morgan cors 

    4. 数据库连接文件

    在项目根目录下新建文件夹models,在models中新建danmaku.js文件

    const mysql = require('mysql2/promise');const pool = mysql.createPool({host: 'localhost',user: 'root',password: 'your_password',database: 'danmaku_db',waitForConnections: true,connectionLimit: 10,queueLimit: 0
    });module.exports = pool;

    5. 获取弹幕接口

    在项目根目录下新建文件夹routes,在routes中新建get.js文件

    const express = require('express');
    const router = express.Router(); // 使用 express.Router() 创建路由实例
    const pool = require('../models/danmaku');// 处理 GET 请求
    router.get('/', async (req, res) => {console.log('GET请求');const { videoId, limit } = req.query; // 从查询参数获取 videoId 和 limit// 参数验证if (!videoId) {return res.status(400).json({ code: 1, msg: 'videoId 参数是必需的' });}try {const [rows] = await pool.query('SELECT time, type, color, author, text FROM danmaku WHERE player = ? ORDER BY time',[videoId]);let data = rows.map(item => [parseFloat(item.time),parseInt(item.type),parseInt(item.color.replace('#', ''), 16),item.author,item.text]);if (limit) {const parsedLimit = parseInt(limit);if (isNaN(parsedLimit) || parsedLimit <= 0) {return res.status(400).json({ code: 1, msg: 'limit 参数必须是正整数' });}data = data.slice(-parsedLimit);}res.json({code: 0,data});} catch (error) {console.error('获取弹幕失败:', error);res.status(500).json({ code: 1, msg: '获取弹幕失败' });}
    });module.exports = router;

    6. 添加弹幕接口

    在routes中新建post.js文件

    const express = require('express');
    const router = express.Router();
    const pool = require('../models/danmaku');
    const bodyParser = require('body-parser');router.use(bodyParser.json());router.post('/', async (req, res) => {console.log('POST请求');const { id, author, time, text, color, type } = req.body;const ip = req.ip;const referer = req.headers.referer || '';try {const [result] = await pool.query('INSERT INTO danmaku (player, author, time, text, color, type, ip, referer) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',[id, author, time, text, color, type, ip, referer]);res.json({code: 0,data: {id: result.insertId,player: id,author,time,text,color,type,ip,referer,date: new Date().getTime()}});} catch (error) {console.error('添加弹幕失败:', error);res.status(500).json({ code: 1, msg: '添加弹幕失败' });}
    });module.exports = router;

    7. 主应用文件

    在项目根目录下创建app.js文件

    const express = require('express');
    const app = express();
    const getRouter = require('./routes/get');
    const postRouter = require('./routes/post');
    const morgan = require('morgan');
    const cors = require('cors'); // 引入 cors 中间件// 使用 cors 中间件处理跨域请求
    app.use(cors());// 使用 morgan 作为日志中间件,记录更详细的请求信息
    app.use(morgan('combined'));app.use(express.json());// 使用 /v3 作为基础路径
    app.use('/v3', getRouter);
    app.use('/v3', postRouter);// 全局错误处理中间件
    app.use((err, req, res, next) => {console.error('发生未捕获的异常:', err);res.status(500).json({ code: 1, msg: '服务器内部错误' });
    });const PORT = 3000;
    app.listen(PORT, (err) => {if (err) {console.error(`无法启动服务器:`, err);} else {console.log(`弹幕服务器运行在 http://localhost:${PORT}`);}
    });

    8. 目录结构

    9. 运行服务器

    在终端内运行命令:

    node app.js

     出现以下界面说明运行成功

    八、接口测试

    1. get测试

    在浏览器中输入链接:http://localhost:3000/v3?videoId=test&limit=10

     出现以上界面说明请求接口成功,获取弹幕失败为数据库问题,把数据库配置改成自己本地的就可以了:

    const mysql = require('mysql2/promise');const pool = mysql.createPool({host: '127.0.0.1',      //使用localhost可能会连接失败user: 'root',password: '123456',database: 'danmaku_db',waitForConnections: true,connectionLimit: 10,queueLimit: 0
    });module.exports = pool;

    最终的效果应是这样的:

    2.post测试

    post测试就不能直接使用浏览器,这里需要用到接口测试软件postman,如果没有就要自己在HTML里面写一个接口请求,比较麻烦,后面会直接写一个DPlayer的引用测试。

    打开 Postman

    • 在 Postman 中,选择 POST 方法。

    • 在请求 URL 输入框中输入 http://localhost:3000/v3

    设置请求头

    • 点击 Headers 标签。

    • 添加一个请求头,Content-Type 设置为 application/json

    设置请求体

    • 点击 Body 标签。

    • 选择 raw 单选按钮,并从下拉列表中选择 JSON

    • 在文本框中输入以下 JSON 数据:

      {"id": "test","author": "user1","time": 20.0,"text": "这是一条新弹幕","color": "#FFFFFF","type": 1
      }

    发送请求

    • 点击 Send 按钮发送请求。

    • 检查响应,确保服务器返回了正确的结果。

     检查数据库是否成功插入了数据

    九、在DPlayer中使用

    1.新建HTML文件

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><title>视频弹幕演示</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.css">
    </head><body><div id="dplayer"></div><script src="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js"></script><script>const videoId = 'test'; // ❗ 替换为实际视频 ID(如 1028,需与后端一致)const dp = new DPlayer({container: document.getElementById('dplayer'),video: {url: 'video/test.mp4', // 视频路径type: 'mp4',name: '演示视频'},danmaku: {id: videoId, // 必须与后端路由中的 :id 一致api: 'http://127.0.0.1:3000/', // 后端弹幕服务根路径addition: [// 外挂弹幕//`http://127.0.0.1:3000/` ]}});// 监听 DPlayer 的弹幕发送事件dp.on('danmaku_send', (danmaku) => {console.log('发送请求')console.log('视频ID:' + videoId)});</script>
    </body></html>

    将视频路径“video/test.mp4”换成你自己项目视频所在的路径,比如我的项目结构如下:

    2. 弹幕加载

    直接在新建的HTML页面上按快捷键:“Alt+L+O”或右键菜单Open with Live Server,没有该选项需要先安装插件“Live Server”,将自动打开默认浏览器。

    打开开发者工具,切换到网络页面,刷新当前网页,网络请求没有变红,并且返回相应数据说明弹幕查询成功;

     

    出现相应的弹幕说明DPlayer解析我们的接口数据成功。

    3.发送弹幕测试

    • 该请求没有变红,并且返回了相应的数据;

    • 数据库也增加了这条数据;

    • 视频上也有相应的弹幕;

    以上情况都出现了,说明弹幕发送成功。

    十、服务器日志

    如果其中某个操作没有成功,就需要查看服务器的日志,重复没有成功操作,查看终端是否输出错误信息,根据错误信息定位错误。

    比如,我执行发送弹幕的操作没有成功,查看日志输出为:“Data too long for column 'color' at row 1”,插入数据库的长度太长,需要将color字段的长度从varchar(10)改成varchar(20)。

    十一、总结

    一个非常简陋的Node.js后端服务项目,基本都是用别人写好的东西,感觉还是挺适合初次接触Node.js的同学的。

    涉及的技术也很浅:

    1.前端:HTML、Javascript;

    2.后端:Node.js;

    3.接口测试:postman ;

    相关文章:

    【Node.js 】在Windows 下搭建适配 DPlayer 的轻量(简陋)级弹幕后端服务

    一、引言 DPlayer官网&#xff1a;DPlayer 官方弹幕后端服务&#xff1a;DPlayer-node MoePlayer/DPlayer-node&#xff1a;使用 Docker for DPlayer Node.js 后端&#xff08;https://github.com/DIYgod/DPlayer&#xff09; 本来想直接使用官网提供的DPlayer-node直接搭建…...

    OpenSSH配置连接远程服务器MS ODBC驱动与Navicat数据库管理

    OpenSSH配置连接远程服务器MS ODBC驱动与Navicat数据库管理 目录 OpenSSH配置连接远程服务器MS ODBC驱动与Navicat数据库管理 一、MS ODBC驱动 1.1、安装到Windows后的表现形式 1.2、版本的互斥性 1.3、安装程序 1.4、配置后才可用 二、Navicat数据库管理工具 2.1、安…...

    织梦dedecms调用会员详细字段信息

    织梦如何调用会员详细信息&#xff1a; 在include/extend.func.php function GetMemberInfos($fields,$mid){ global $dsql; if($mid < 0){ $revalue "Error"; } else{ $row$dsql->GetOne("sele ct * fr…...

    MySQL 8.0 忘记登录密码 mysqld --init-file重置

    看到了很多跳过授权表的办法&#xff0c;这里通过mysqld --init-file办法。 适用情况&#xff1a; 服务器可以启动但无法登录/忘记登录密码。 一、首先停止 MySQL 服务&#xff1a; 按下 Win R 组合键&#xff0c;输入 services.msc 并点击“确定”&#xff0c;打开“服务”…...

    Python 学习路线与笔记跳转(持续更新笔记链接)

    这里写目录标题 Python 学习路线与笔记Python 简介学习路线第一阶段&#xff1a;Python 基础第二阶段&#xff1a;Python 进阶第三阶段&#xff1a;实用库与框架第四阶段&#xff1a;DevOps 与 Python第五阶段&#xff1a;最佳实践与高级技巧 学习资源官方资源在线学习平台书籍…...

    操作系统:计算机世界的基石与演进

    一、操作系统的本质与核心功能 操作系统如同计算机系统的"总管家"&#xff0c;在硬件与应用之间架起关键桥梁。从不同视角观察&#xff0c;其核心功能呈现多维价值&#xff1a; 硬件视角的双重使命&#xff1a; 硬件管理者&#xff1a;通过内存管理、进程调度和设…...

    Codeium 免费的AI编程助手

    Codeium 由 Exafunction 团队&#xff08;主要也是美国华人&#xff09;开发的一款免费AI编程助手&#xff0c;是一个建立在顶尖AI技术上的代码加速工具&#xff0c;其背后的老板非常厉害&#xff0c;据说投资过马斯克的SpaceX。Codeium 本身具有颇多的亮点&#xff0c;支持70种…...

    在MySQL Shell里 重启MySQL 8.4实例

    前一段时间看到MySQL官方视频的Oracle工程师在mysql shell里面重启mysql实例&#xff0c;感觉这个操作很方便&#xff0c;所以来试试&#xff0c;下面为该工程师的操作截图 1.MySQL Shell 通过root用户连上mysql&#xff0c;shutdown mysql实例 [rootmysql8_3 bin]# mysqlshMy…...

    FANUC机器人GI与GO位置数据传输设置

    FANUC机器人GI与GO位置数据传输设置&#xff08;整数小数分开发&#xff09; 一、概述 在 Fanuc 机器人应用中&#xff0c;如果 IO 点位足够&#xff0c;可以利用机器人 IO 传输位置数据及偏移位置数据等。 二、操作步骤 1、确认通讯软件安装 首先确认机器人控制柜已经安装…...

    LeetCode 24 两两交换链表中的节点

    ​给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2,1…...

    低代码平台开发手机USB-HID调试助手

    项目介绍 USB-HID调试助手是一种专门用于调试和测试USB-HID设备的软件工具。USB-HID设备是一类通过USB接口与计算机通信的设备&#xff0c;常见的HID设备包括键盘、鼠标、游戏控制器、以及一些专用的工业控制设备等。 主要功能包括&#xff1a; 数据监控&#xff1a;实时监控和…...

    Java 深度与实战 · 每日一读 :高频面试真题解析 · ReentrantLock / CAS / AQS 篇

    ReentrantLock 深层分析&#xff1a;CAS、AQS原理全揭秘 此文为「Java 深度与实战每日一读」系列第1篇&#xff0c;原创专栏&#xff0c;全篇不含水分&#xff0c;该系列整个面向&#xff1a;初学、进阶、面试、原理、实战&#xff0c;全综合型导向。 目标&#xff1a;让任何级…...

    golang goroutine(协程)和 channel(管道) 案例解析

    文章目录 goroutine和channel概念开启线程与channel简单通信流程多个工作协程并发执行流程 goroutine和channel概念 goroutine(协程)&#xff0c;一般我们常见的是进程&#xff0c;线程&#xff0c;进程可以理解为一个软件在运行执行的过程&#xff0c;线程跟协程比较类似&…...

    亚组风险比分析与可视化

    1. 结果解读 1.1 风险比概述 1.1.1 风险比基本概念 风险比(Hazard Ratio)用于衡量治疗组与对照组事件发生的风险差异。 风险比为1,表示两组风险相同;小于1,治疗组风险低;大于1,治疗组风险高。 1.1.2 性别亚组分析 A性风险比小于1,表明治疗对A性有积极效果,风险降低。…...

    计算机网络核心知识点全解析(面试通关版)

    一、网络体系结构&#xff1a;从OSI到TCP/IP的分层设计 1.1 七层模型与四层模型对比 OSI七层模型核心功能TCP/IP四层对应典型协议生活类比应用层为应用程序提供服务&#xff08;如文件传输、邮件、Web浏览&#xff09;应用层HTTP、FTP、SMTP、DNS快递面单信息&#xff08;收件…...

    使用 Frida 绕过 iOS 应用程序中的越狱检测

    在这篇博文中,我们将介绍**Frida**,它是用于移动应用程序安全分析的真正有趣的工具之一。 我们在高级 Android 和 iOS 漏洞利用培训中也深入讲解了这一点,您可以在这里注册 -培训链接 即使您从未使用过 Frida,本文也将作为指南,帮助您进入 Frida 的世界,进行移动应用程…...

    【博客系统】博客系统第一弹:博客系统项目配置、MyBatis-Plus 实现 Mapper 接口、处理项目公共模块:统一返回结果、统一异常处理

    案例综合练习 - 博客系统 本节目标 从 0 到 1 完成博客系统后端项目的开发。 前言 通过前面课程的学习&#xff0c;我们掌握了 Spring 框架和 MyBatis 的基本使用&#xff0c;并完成了图书管理系统的常规功能开发。接下来我们系统地从 0 到 1 完成一个项目的开发。 项目介绍 …...

    如何通过挖掘需求、SEO优化及流量变现成功出海?探索互联网产品的盈利之道

    挖掘需求&#xff0c;优化流量&#xff0c;实现变现&#xff1a;互联网出海产品的成功之路 在当今全球化的数字时代&#xff0c;越来越多的企业和个人选择将业务扩展到国际市场。这一趋势不仅为企业带来了新的增长机会&#xff0c;也为个人提供了通过互联网产品实现盈利的途径…...

    车载功能测试-车载域控/BCM控制器测试用例开发流程【用例导出方法+优先级划分原则】

    目录 1 摘要2 位置灯手动控制简述2.1 位置灯手动控制需求简述2.2 位置灯手动控制逻辑交互图 3 用例导出方法以及优先级原则3.1 用例导出方法3.1.1 用例导出方法介绍3.1.2 用例导出方法关键差异分析 3.2 优先级规则3.2.1 优先级划分的核心原则3.2.2 具体等级定义与判定标准 3.3 …...

    基于OpenMV+STM32+OLED与YOLOv11+PaddleOCR的嵌入式车牌识别系统开发笔记

    基于OpenMV、STM32与OLED的嵌入式车牌识别系统开发笔记 基于OpenMV、STM32与OLED的嵌入式车牌识别系统开发笔记系统架构全景 一、实物演示二、OpenMV端设计要点1. 硬件配置优化2. 智能帧率控制算法3. 数据传输协议设计 三、PyTorch后端核心实现&#xff1a;YOLOv11与PaddleOCR的…...

    MCP实战-本地MCP Server + Client实战

    概述 本文开发一个MCP的Client和Server。然后通过本地模式来运行&#xff0c;并获取到server的结果。 MCP Server开发 import anyio import click import mcp.types as types from mcp.server.lowlevel import Server from pydantic import FileUrlSAMPLE_RESOURCES {"…...

    w~嵌入式C语言~合集4

    我自己的原文哦~ https://blog.51cto.com/whaosoft/13870376 一、STM32怎么选型 什么是 STM32 STM32&#xff0c;从字面上来理解&#xff0c;ST是意法半导体&#xff0c;M是Microelectronics的缩写&#xff0c;32表示32位&#xff0c;合起来理解&#xff0c;STM32就是指S…...

    lightrag : from lightrag.utils import EmbeddingFunc 报错

    原因&#xff1a; 1. 同时安装了lightrag与lightrag-hku 解决方法&#xff1a; 卸载原有的lightrag与lightrag-hku&#xff0c;只安装lightrag-hku pip install lightrag-hku...

    ppt流程图怎么?ppt流程图模板大全

    ppt流程图怎么&#xff1f;ppt流程图剪头模板&#xff0c;ppt流程图模板大全: ppt流程图_模板素材_PPT模板_ppt素材_免抠图片_AiPPTer...

    AWS中国区ICP备案全攻略:流程、注意事项与最佳实践

    导语 在中国大陆地区开展互联网业务时,所有通过域名提供服务的网站和应用必须完成ICP备案(互联网内容提供商备案)。对于选择使用AWS中国区(北京/宁夏区域)资源的用户,备案流程因云服务商的特殊运营模式而有所不同。本文将详细解析AWS中国区备案的核心规则、操作步骤及避坑…...

    腾讯云服务器安全——服务防火墙端口放行

    点击服务进入安全策略 添加规则...

    对局匹配--stl+模拟

    1.模拟&#xff0c;先找匹配对数&#xff0c;然后减 2.特殊情况&#xff0c;k0 3.stl容器使用&#xff0c;lower_bound https://www.luogu.com.cn/problem/P8656 #include<bits/stdc.h> using namespace std; #define N 100011 typedef long long ll; typedef pair&…...

    K8S安全认证

    一。用户认证的基本框架 在K8S集群中&#xff0c;客户端通常有两类&#xff1a; 1.User Account&#xff1a;一般独立于K8S之外的其他服务管理的用过户账号 2.Service Account&#xff1a;K8S管理的账号&#xff0c;用于为Pod中的服务进程在访问K8S提供身份标识 ApiServer是…...

    mybatis-plus里的com.baomidou.mybatisplus.core.override.MybatisMapperProxy 类的详细解析

    以下是 com.baomidou.mybatisplus.core.override.MybatisMapperProxy 类的详细解析&#xff1a; 1. 类的作用 MybatisMapperProxy 是 MyBatis-Plus 框架中用于实现 Mapper 接口动态代理的核心类。它继承自 MyBatis 的 MapperProxy&#xff0c;并扩展了以下功能&#xff1a; …...

    在java程序中,类,进程,线程他们之间的关系以及main方法与他们之间的关系

    在 Java 程序里&#xff0c;类、进程、线程各自有着不同的概念&#xff0c;同时也存在着紧密的联系&#xff0c;下面来详细分析它们之间的关系以及 main 方法和它们的关系。 类 类是 Java 中最基础的编程单元&#xff0c;是一种自定义的数据类型&#xff0c;它定义了对象的属…...