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

大文件上传服务-后端V1V2

文章目录

      • 大文件上传概述:
      • minio分布式文件存储
        • 使用的一些技术
        • 校验MD5的逻辑
      • uploadV1 版本 1
      • uploadv2 版本 2

大文件上传概述:

之前项目做了一个文件上传的功能,最近看到有面试会具体的问这个上传功能的细节,把之前做的项目拿过来总结一下,自己写的一个文件上传服务,如果是单体项目直接就是 file-model,微服务可以给文件单独搞一个服务。

对于大的文件上传由于网络带宽的限制非常的耗时间,可以将文件进行切分,类似于IP数据包重组和分片。

类似于百度网盘一秒上传文件,这个如何实现的呢? 相同的文件上传过一次之后使用了MD5加密的算法,下次就不用等待上传了。

对于海量的文件,如何去存储呢? 这些都是需要去考虑的内容。可以使用轻量级的分布式存储minio来存储文件。复杂一点可以使用 fastDFS 来存储文件。

文件存储 sql 表:

create table file_url_table
(id          int auto_incrementprimary key,file_name   varchar(255)                        not null,file_type   varchar(30)                         not null,file_md5    varchar(32)                         not null,file_url    varchar(512)                        not null,endpoint    varchar(255)                        not null,buck_name   varchar(255)                        not null,object_name varchar(255)                        not null,created_at  timestamp default CURRENT_TIMESTAMP null,updated_at  timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP
);

minio分布式文件存储

后端文件的存储使用分布式文件存储系统minio

一个minio的地址包括:

endpoint:节点的信息 http:ip地址+:端口号

buckName: 桶的基础信息

objectName: 文件夹的信息+文件的名称。

http://xxxxx:9000/powerproject/file/2024/12/01/bbb5ba51d7b65cf4495de91ca55bfa23.mp3

项目中使用 minio

导入minio maven依赖:

<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.7</version>
</dependency>

配置minoConfig,使用Configuration注解,spring在启动的时候会扫描这个类。@bean会创建一个MinioClient,交给Spring容器去管理。


@Configurationpublic class MinioConfig {@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Value("${minio.endpoint}")private String endPoint;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(endPoint).credentials(accessKey, secretKey).build();}
}
  • **@Bean** 注解定义了一个 Spring Bean 方法,用来初始化并提供配置好的 MinioClient
  • 通过自动注入,Spring Boot 会将配置文件中的 minio.accessKey, minio.secretKey, minio.endPoint 自动注入到类的字段中,并将配置好的 MinioClient 实例作为 Bean 提供给整个应用使用。
  • spring启动的时候会扫描到configuration这个包。

断点续传:

通常视频文件都比较大,所以对于媒资系统上传文件的需求要满足大文件的上传要求。http协议本身对上传文件大小没有限制,但是客户的网络环境质量、电脑硬件环境等参差不齐,如果一个大文件快上传完了网断了没有上传完成,需要客户重新上传,用户体验非常差,所以对于大文件上传的要求最基本的是断点续传。

什么是断点续传:

引用百度百科:断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载,断点续传可以提高节省操作时间,提高用户体验性

使用的一些技术

因为上传的结构传进来的都是MultipartFile,但是文件合并完成之后是File类型的,需要将File转为MultipartFile。

  //将木桶的文件 转换成 MultipartFileMultipartFile multipartFile = new MockMultipartFile("file",                           // 表单中文件参数的名字fileName,             // 文件名fileType,                // 文件类型new FileInputStream(outputFile)   // 文件输入流);

MockMultipartFile 的构造函数有四个参数:

  • 第一个参数"file"
    • 这是表单中用于接收文件的字段名。通常是前端表单中的 <input type="file" name="file"> 中的 name 属性值。
    • 例如,在 HTML 表单中,字段可能长这样:
<input type="file" name="file">
- 后端通过 `"file"` 来访问上传的文件。
  • 第二个参数fileName
    • 这是文件的名字,即上传文件时的文件名。它将作为文件在服务器上存储时的名称,或者用作处理文件时的标识符。
    • 例如,fileName 可能是 "document.pdf""image.jpg" 等。
  • 第三个参数fileType
    • 这是文件的 MIME 类型(文件类型)。常见的文件类型如 "application/pdf", "image/jpeg", "text/plain" 等。
    • 在这里,它指定了文件的格式/类型,告诉服务器如何处理该文件。
  • 第四个参数new FileInputStream(outputFile)
    • 这是文件内容的输入流。**FileInputStream**** 用于读取文件内容并将其传递给 **MockMultipartFile**。**
    • outputFile 是一个 File 对象,表示要上传的实际文件。通过 new FileInputStream(outputFile),你可以将文件内容转换为字节流,使得它可以被传递到 MockMultipartFile 中。

MultipartFile 提供了几个常用方法,比如:

  • getName(): 获取文件的字段名。
  • getOriginalFilename(): 获取文件的原始文件名。
  • getBytes(): 获取文件的字节内容。
  • getInputStream(): 获取文件的输入流。
校验MD5的逻辑

对于已经存在的文件,文件的 md5 值都是相同的。文件上传前端解析 md5,查询数据库中是否有数据,如果没有再实现文件上传。

//去数据库中查询这个文件的哈希值是否存在,如果存在就不用上传了,直接拿到这个文件的地址
@GetMapping("/md5")
public AjaxResult getMd5(@RequestParam("md5") String md5) {Map<String, Object> map=fileService.getMd5(md5);return AjaxResult.success(map);
}
@SneakyThrows
@Override
public Map<String, Object> getMd5(String md5) {
// 从数据库查询文件信息
FileEntity file = fileMapper.getMd5(md5);// 如果文件不存在,直接返回 null
if (file == null) {return null;   
}// 获取文件相关信息
String bucketName = file.getBuckName();
String objectName = file.getObjectName();
String fileUrl = file.getFileUrl();
String fileType = file.getFileType();
String fileName = file.getFileName();try {// 检查文件是否存在于 MinIOif (!minioTemplate.isExist(objectName)) {// 文件不存在return null;}
} catch (MinioException e) {// 如果 MinIO 抛出异常,记录异常信息return null;
}// 文件存在,构建返回的 Map
Map<String, Object> result = new HashMap<>();
result.put("url", fileUrl);
result.put("fileType", fileType);
result.put("fileName", fileName);return result;
}

判断文件是否存在

   public boolean isExist(String objectName) throws Exception {StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());return statObjectResponse == null;}

uploadV1 版本 1

画板

上传整个文件。

 @GetMapping("/uploadV1")public AjaxResult uploadFileV1(MultipartFile file) {Map<String, Object> map = fileService.uploadV1(file);return AjaxResult.success(map);}

前置校验,检查文件的大小。 文件不能过大。 限制了一些文件上传的大小 FileType 枚举类

// 通过枚举类校验文件的大小
private void preCheck(MultipartFile file) {
String fileName = file.getOriginalFilename();  //得到原来的名称
String fileSuffix = fileName.substring(fileName.lastIndexOf(".")); // 拿到后缀
FileType fileType = FileType.getFileTypeByExtension(fileSuffix);
if (fileType == null) {throw new ServiceException("不支持的文件格式");
}// 校验文件大小
if (file.getSize() > fileType.getMaxSize()) {throw new ServiceException("文件大小超过" + (fileType.getMaxSize() / (1024 * 1024)) + "MB");
}
}
import java.util.Arrays;
import java.util.List;public enum FileType {//两个属性 一个是文件的扩展名  一个是文件大小IMAGE(Arrays.asList(".jpg", ".png", ".jpeg"), 1024 * 1024 * 50),  // 50MBDOCUMENT(Arrays.asList(".doc", ".xls", ".ppt", ".txt", ".pdf", ".mp3", ".wav", ".ply"), 1024 * 1024 * 100),  // 100MBVIDEO(Arrays.asList(".mp4", ".avi", ".mov"), 1024 * 1024 * 200);  // 200MBprivate List<String> extensions;  // 支持的文件扩展名private long maxSize;  // 最大文件大小// 构造函数FileType(List<String> extensions, long maxSize) {this.extensions = extensions;this.maxSize = maxSize;}public List<String> getExtensions() {return extensions;}public long getMaxSize() {return maxSize;}// 根据文件扩展名获取文件类型public static FileType getFileTypeByExtension(String fileSuffix) {for (FileType type : FileType.values()) {if (type.getExtensions().contains(fileSuffix)) {return type;}}return null;  // 如果没有匹配的文件类型,返回 null}
}

不同的文件放在不同的文件夹下面。

image开头的 存储一些 .jpg、.jped,.png文件。

file 开头的存放 .doc,.xls文件。 使用枚举类可以来实现动态的管理。 设置文件存储路径,使用日期的存储不同,不用的文件类型存储不同的路径

	String fileBucket = getFileBucket(fileSuffix);if (fileBucket == null) {return null;}// 获取当前日期Date now = new Date();// 使用 SimpleDateFormat 来格式化日期为 "yyyy/MM/dd" 格式DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");String date = sdf.format(now);// 组合最终的文件夹路径:如 "image/2024/11/30/"return fileBucket + date + "/";}private static String getFileBucket(String fileSuffix) {return FileCategory.getBucketPrefixByExtension(fileSuffix);}
package com.njitzx.fileupload.enu;import java.util.Arrays;
import java.util.List;public enum FileCategory {IMAGE(Arrays.asList(".jpg", ".jpeg", ".png", ".gif"), "image/"),DOCUMENT(Arrays.asList(".doc", ".xls", ".ppt", ".txt", ".pdf", ".mp3", ".wav", ".ply"), "file/"),VIDEO(Arrays.asList(".mp4", ".avi", ".mov"), "video/"),AUDIO(Arrays.asList(".mp3", ".wav"), "audio/");private List<String> extensions;  // 支持的文件扩展名private String bucketPrefix;      // 存储路径前缀// 构造函数FileCategory(List<String> extensions, String bucketPrefix) {this.extensions = extensions;this.bucketPrefix = bucketPrefix;}// 获取支持的文件扩展名列表public List<String> getExtensions() {return extensions;}// 获取对应的存储路径public String getBucketPrefix() {return bucketPrefix;}// 根据文件扩展名获取对应的存储路径public static String getBucketPrefixByExtension(String fileSuffix) {for (FileCategory category : FileCategory.values()) {if (category.getExtensions().contains(fileSuffix)) {return category.getBucketPrefix();}}return null;  // 如果没有找到对应的类型,返回 null}
}

上传的Service代码。

文件上传成功后需要将信息插入到文件表中去。 文件存储 service 方法:

public Map<String, Object> uploadV1(MultipartFile file) {
//文件的名称
String md5Name = MD5Util.getFileMD5(file);String fileName = file.getOriginalFilename();String fileSuffix = fileName.substring(fileName.lastIndexOf("."));String folderName = generateFolderName(fileSuffix); //文件夹名称
//拼接objectName
String objectName = folderName + md5Name + fileSuffix;  //objectName//拼接文件的全文路径
String fileUrl = endPoint + "/" + bucketName + "/" + objectName; //完整的URL//放入到minio中去
minioTemplate.pubObject(objectName, file);  //存入到minio中去//将文件上传信息插入到数据库中
FileEntity file1 = FileEntity.builder().fileName(fileName).fileType(fileSuffix.substring(1))
.fileUrl(fileUrl).endpoint(endPoint).buckName(bucketName).objectName(objectName).createdAt(new Date()).updatedAt(new Date()).fileMd5(md5Name).build();
//插入文件信息
HashMap<String, Object> map = new HashMap<>();
fileMapper.insertFile(file1);//存储map中返回给前端  文件url、name、文件类型
map.put("fileUrl", fileUrl);
map.put("fileName", fileName);
map.put("fileType", fileSuffix.substring(1));return map;
}

mapper的插入语句

  <!-- 插入文件记录 --><insert id="insertFile" parameterType="com.njitzx.fileupload.pojo.FileEntity">INSERT INTO file_url_table (file_name, file_type, file_md5, file_url, endpoint, buck_name, object_name,created_at, updated_at)VALUES (#{fileName}, #{fileType}, #{fileMd5}, #{fileUrl}, #{endpoint}, #{buckName}, #{objectName}, #{createdAt},#{updatedAt})</insert>

测试接口:

uploadv2 版本 2

前端上传的大文件 在前端进行切片传输,后端接收切片的文件,整合组合成一个新的文件。

涉及到切片,类似于IP数据包重组,标识一个文件的信息。

fileId  文件信息的唯一标识
currentChunk 当前的块数
totalChunk 总的块数
File 文件的数据

类似于 IP 数据包,切片的那个字段需要有当前第一块,后面是否还有数据包信息。

    @PostMapping("/uploadV2")public AjaxResult uploadFileV2(@RequestParam("fileID") Long fileID,           // 接收文件ID@RequestParam("currentChunk") Integer currentChunk, // 接收当前块@RequestParam("totalChunk") Integer totalChunk,     // 接收总块数@RequestParam("file") MultipartFile file           // 接收文件数据) throws IOException {fileService.uploadV2(fileID, currentChunk, totalChunk, file);return AjaxResult.success();}

通过System.getProperty(“user.dir”) 拿到当前的项目目录。

在当前目录下面创建一个upload文件夹,通过fIleId来区分不同的文件。

文件的名称就是当前的 chunk_+当前的块名称。 将传过来的小文件保存起来。

@SneakyThrows
@Override
public void uploadV2(Long fileID, Integer currentChunk, Integer totalChunk, MultipartFile file) {//当前的文件夹String currentDir = System.getProperty("user.dir");String tempDir = currentDir + "/upload/" + fileID;File dir = new File(tempDir);if (!dir.exists()) {dir.mkdirs();}// 保存当前分片String chunkPath = tempDir + "/chunk_" + currentChunk;File chunkFile = new File(chunkPath);file.transferTo(chunkFile);// 记录当前上传分片,等待后续合并System.out.println("保存分片:" + chunkPath);// 如果所有分片上传完毕,返回合并请求
}

前端在所有的分片上传成功之后进行合并请求。

通过get请求 传过来 文件的id、文件名称、文件类型等。

@GetMapping("/merge")
public AjaxResult mergeFile(@RequestParam("fileID") Long fileID, @RequestParam("fileType") String fileType,@RequestParam("fileName") String fileName) throws IOException {Map<String, Object> map = fileService.merge(fileID, fileType, fileName);return AjaxResult.success();
}

合并的步骤是这样的,首先获取到所有的分片文件。按照分片编号进行排序。将所有的小的文件按照顺序组成一个大的文件,这就又回到了第一步,使用uploadv1将文件重组上传。

@SneakyThrows
@Override
public Map<String, Object> merge(Long fileID, String fileType, String fileName) {String currentDir = System.getProperty("user.dir"); //拿到当前项目的目录String type = fileType.substring(fileType.lastIndexOf("/") + 1);String tempDir = currentDir + "/upload/" + fileID;File dir = new File(tempDir);if (!dir.exists()) {throw new ServiceException("分片文件不存在");}// 获取所有的分片文件List<File> chunkFiles = Arrays.asList(Objects.requireNonNull(dir.listFiles()));// 按照分片编号排序chunkFiles.sort(Comparator.comparingInt(file -> Integer.parseInt(file.getName().split("_")[1])));// 合并所有分片文件File outputFile = new File(currentDir + "/upload/" + fileID + "." + type);//true标识不覆盖文件,在原有的文件后面添加。try (FileOutputStream outputStream = new FileOutputStream(outputFile, true)) {//遍历所有的小的文件for (File chunk : chunkFiles) {try (FileInputStream inputStream = new FileInputStream(chunk)) {byte[] buffer = new byte[1024];int len;while ((len = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, len);}}}}//将木桶的文件 转换成 MultipartFileMultipartFile multipartFile = new MockMultipartFile("file",                           // 表单中文件参数的名字fileName,             // 文件名fileType,                // 文件类型new FileInputStream(outputFile)   // 文件输入流);// 调用 fileService.uploadV1 方法上传文件Map<String, Object> map = uploadV1(multipartFile);// 返回合并后的文件URLreturn map;
}

上面的内容还是不够完整,因为文件临时存储在本地上,最后合并起来再放入到mino中,还是将大的文件存放到服务器上,如果网络中断并且时间也是较长的。应该将切片的文件存放到minio中去,最后在minio中进行文件的合并。

文件切片上传成功:

相关文章:

大文件上传服务-后端V1V2

文章目录 大文件上传概述:minio分布式文件存储使用的一些技术校验MD5的逻辑 uploadV1 版本 1uploadv2 版本 2 大文件上传概述: 之前项目做了一个文件上传的功能,最近看到有面试会具体的问这个上传功能的细节&#xff0c;把之前做的项目拿过来总结一下&#xff0c;自己写的一个…...

Single-Model and Any-Modality for Video Object Tracking——2024——cvpr-阅读笔记

Single-Model and Any-Modality for Video Object Tracking 摘要相关工作创新处MethodShared embeddingModal promptingRGB Tracker based on TransformerOverall ExperiimentDatasetRGB-D samples are sourced from DepthTrackRGB-T samples are extracted from LasHeRRGB-E s…...

阳振坤:AI 大模型的基础是数据,AI越发达,数据库价值越大

2024年1月12日&#xff0c;第四届OceanBase数据库大赛决赛在北京圆满落幕。在大赛的颁奖典礼上&#xff0c;OceanBase 首席科学家阳振坤老师为同学们献上了一场主题为“爱上数据库”的公开课&#xff0c;他不仅分享了个人的成长历程&#xff0c;还阐述了对数据库行业现状与未来…...

Linux磁盘空间不足,12个详细的排查方法

在Linux系统运维过程中&#xff0c;磁盘空间不足是一个常见且棘手的问题。当磁盘空间被占满时&#xff0c;系统的正常运行会受到影响&#xff0c;甚至可能导致服务中断。因此&#xff0c;迅速有效地排查和解决磁盘空间问题显得尤为重要。本文将详细介绍16个排查Linux磁盘空间问…...

Spring Web MVC综合案例

承接上篇文章——Spring Web MVC探秘&#xff0c;在了解Spring Web MVC背后的工作机制之后&#xff0c;我们接下来通过三个实战项目&#xff0c;来进一步巩固一下前面的知识。 一、计算器 效果展示&#xff1a;访问路径&#xff1a;http://127.0.0.1:8080/calc.html 前端代码&a…...

微软预测 AI 2025,AI Agents 重塑工作形式

1月初&#xff0c;微软在官网发布了2025年6大AI预测&#xff0c;分别是&#xff1a;AI模型将变得更加强大和有用、AI Agents将彻底改变工作方式、AI伴侣将支持日常生活、AI资源的利用将更高效、测试与定制是开发AI的关键以及AI将加速科学研究突破。 值得一提的是&#xff0c;微…...

lvgl性能调优

LV_USE_PERFORMANCE lvgl_performance 是 LVGL 提供的性能分析工具&#xff0c;可以帮助开发者评估和优化图形库的性能。在一些特定的版本中&#xff0c;lvgl_performance 是一个宏或者工具&#xff0c;用来分析性能瓶颈&#xff0c;特别是图形渲染的效率。 下面是如何使用 l…...

CSS实现实现票据效果 mask与切图方式

一、“切图”的局限性 传统的“切图”简单暴力,但往往缺少适应性。 适应性一般有两种,一是尺寸自适应,二是颜色可以自定义。 举个例子,有这样一个优惠券样式 关于这类样式实现技巧,之前在这篇文章中有详细介绍: CSS 实现优惠券的技巧 不过这里略微不一样的地方是,两个…...

STL--list(双向链表)

目录 一、list 对象创建 1、默认构造函数 2、初始化列表 3、迭代器 4、全0初始化 5、全值初始化 6、拷贝构造函数 二、list 赋值操作 1、赋值 2、assign&#xff08;迭代器1&#xff0c;迭代器2&#xff09; 3、assign&#xff08;初始化列表&#xff09; 4、assig…...

ZooKeeper 中的 ZAB 一致性协议与 Zookeeper 设计目的、使用场景、相关概念(数据模型、myid、事务 ID、版本、监听器、ACL、角色)

参考Zookeeper 介绍——设计目的、使用场景、相关概念&#xff08;数据模型、myid、事务 ID、版本、监听器、ACL、角色&#xff09; ZooKeeper 设计目的、特性、使用场景 ZooKeeper 的四个设计目标ZooKeeper 可以保证如下分布式一致性特性ZooKeeper 是一个典型的分布式数据一致…...

“深入浅出”系列之C++:(11)推荐一些C++的开源项目

1. SQLiteCpp - 简单易用的Sqlite C封装库 仓库地址&#xff1a;https://github.com/SRombauts/SQLiteCpp 简介&#xff1a;SQLiteCpp是一个对Sqlite数据库进行C封装的开源库&#xff0c;代码行数约2,500行。它提供了简洁易用的接口&#xff0c;使得在C项目中操作Sqlite数据库…...

《重生到现代之从零开始的C++生活》—— 类和对象2

类的默认成员函数 默认成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数&#xff0c;一个类会默认生成6个成员函数 构造函数 构造函数时特殊的成员函数&#xff0c;构造函数的初始化对象 函数名与类名相同 没有返回值 对象实例化的时候胡自动调用构造…...

“UniApp的音频播放——点击视频进入空白+解决视频播放器切换视频时一直加载的问题”——video.js、video-js.css

今天&#xff0c;又解决了一个单子“UniApp的音频播放——点击视频进入空白解决视频播放器切换视频时一直加载的问题” 一、问题描述 在开发一个基于 video.js 的视频播放器时&#xff0c;用户通过上下滑动切换视频时&#xff0c;视频一直处于加载状态&#xff0c;无法正常播放…...

【Pandas】pandas Series transform

Pandas2.2 Series Function application, GroupBy & window 方法描述Series.apply()用于将一个函数应用到 Series 的每个元素或整个 SeriesSeries.agg()用于对 Series 数据进行聚合操作Series.aggregate()用于对 Series 数据进行聚合操作Series.transform()用于对 Series…...

【博客之星2024年度总评选】年度回望:我的博客之路与星光熠熠

【个人主页】Francek Chen 【人生格言】征途漫漫&#xff0c;惟有奋斗&#xff01; 【热门专栏】大数据技术基础 | 数据仓库与数据挖掘 | Python机器学习 文章目录 前言一、个人成长与盘点&#xff08;一&#xff09;机缘与开端&#xff08;二&#xff09;收获与分享 二、年度创…...

飞牛 使用docker部署Watchtower 自动更新 Docker 容器

Watchtower是一款开源的Docker容器管理工具&#xff0c;其主要功能在于自动更新运行中的Docker容器 Watchtower 支持以下功能&#xff1a; 自动拉取镜像并更新容器。 配置邮件通知。 定时执行容器更新任务。 compose搭建Watchtower 1、新建文件夹 先在任意位置创建一个 w…...

【Block总结】TAdaConv时序自适应卷积,轻量高效的时间建模卷积|即插即用

论文解读&#xff1a;Temporally-Adaptive Models for Efficient Video Understanding 论文信息 标题&#xff1a;Temporally-Adaptive Models for Efficient Video Understanding 发表时间&#xff1a;2023年 作者&#xff1a;黄子渊等 论文链接&#xff1a;arXiv 论文 代…...

Spring Boot 项目启动报错 “找不到或无法加载主类” 解决笔记

一、问题描述 在使用 IntelliJ IDEA 开发基于 Spring Boot 框架的 Java 程序时&#xff0c;原本项目能够正常启动。但在后续编写代码并重建项目后&#xff0c;再次尝试运行却出现了 “错误&#xff1a;找不到或无法加载主类 com.example.springboot.SpringbootApplication” 的…...

CSS 网络安全字体

适用于 HTML 和 CSS 的最佳 Web 安全字体 下面列出了适用于 HTM L和 CSS 的最佳 Web 安全字体&#xff1a; Arial (sans-serif)Verdana (sans-serif)Helvetica (sans-serif)Tahoma (sans-serif)Trebuchet MS (sans-serif)Times New Roman (serif)Georgia (serif)Garamond (se…...

Linux高并发服务器开发 第十五天(fork函数)

目录 1.fork 函数 1.1创建子进程 1.2getpid 函数 1.3getppid 函数 1.4getgid函数 1.5循环创建 n 个子进程 1.6fork后父子进程异同 1.6.1读时共享&#xff0c;写时复制 1.6.2fork后父子进程共享 1.6.3gdb调试父子进程 1.fork 函数 pid_t fork(void); 成功&#xff1a;…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...