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

固态存储设备固件升级方案

1. 前言

随着数字化时代的发展,数字数据的量越来越大,相应的数据存储的需求也越来越大,存储设备产业也是蓬勃发展。存储设备产业中,发展最为迅猛的则是固态存储(Solid State Storage,SSS)。数字化时代,海量的数据,需要海量的存储设备。可以说,固态存储设备是数字化时代最重要的基础设施。
为了解决发现的Bug,安全漏洞,或者为了提升性能,固态存储设备也有升级其固件的需求。固态存储设备种类繁多,有可以随身携带的U盘、TF卡,也有手机中的eMMC,UFS,还有电脑中的固态硬盘(SSD),更有各种云背后的分布式存储系统中大量使用的各种固态存储设备。不同应用场景,其使用方式也不同,那么相应的升级方式也有可能不同。本文尝试全面介绍一下不同应用场景下的固态存储设备的固件升级方案。

2. 固态存储设备

固态存储设备的主要构成为存储介质,控制芯片和一些外置电子元器件。固态存储设备的主要存储介质为非易失性存储器,其主要为NAND Flash。控制芯片的主要作用是连接NAND Flash和主机存储接口,并管理存储在NAND Flash上的数据。
主机存储接口不同,应用的场景也不同。其主要分为:
● USB接口,主要用于移动存储;
● SD接口,主要用于小型电子设备,如相机,监控设备等;
● eMMC接口,主要用于手机、平板和一些嵌入式设备,如智能电视,车机等;
● UFS接口,主要用于手机;
● SATA接口,主要用于个人电脑;
● PCIe接口,主要用于对性能有更高要求的企业级存储,如分布式存储,云存储等。

3. 升级方案

存储设备是否支持固件升级,需要两个方面的支持,存储设备固件算法支持升级,并且有升级工具。

3.1. 固件算法

存储设备升级成功,或者万一在升级过程中断电,都不能影响存储设备上之前存放的用户数据。升级算法设计要点:
● 用户数据的正确性,即L2P表(存储设备逻辑到NAND Flash物理地址映射表)不能发生改变。
○ FTL算法设计的时候,需要将L2P表等影响用户数据的算法数据结构和其他算法数据结构分块存储。因为升级固件,必须重新写入算法二进制文件和重新配置Boot信息,因为NAND Flash的块必须擦除了才能写,所以固件二进制文件和Boot信息必须和L2P表分块存储。
● 异常行为的安全性,即升级过程中,发生异常,重新上电时,能够恢复原有的状态。
○ 升级的操作过程是日志型的,每一步操作都有记录,只有最后升级成功,并且有CheckSum校验机制来保证操作的完整性。
○ 升级算法的设计,新旧算法都保留,每次升级成功之后,将新算法头中索引加1,这样每次启动后,检测到两个算法,并通过CheckSum校验算法的完整性,最后比较算法头中的索引值,启动索引较大的算法。

3.2. 升级流程

3.2.1. 移动存储设备

移动存储设备U盘/TF卡,基本都可以通过USB接口接入电脑,电脑的操作系统主要包括Windows和Linux。所以针对移动存储设备,主要考虑制作系统软件来应对此类升级。为了减少软件开发工作,建议使用跨平台方案,保证最大限度的复用代码。为了更好地操作底层API,并且有效率的开发软件,采用C++作为软件开发语言,选用Qt作为跨平台的开发框架,并且都采用g++编译器。无论是在Linux平台,还是在Windows平台,升级的基本流程基本是相同的。如下图:
在这里插入图片描述

抽象出Linux和Windows下不同点,统一抽象的接口,然后复用宏WIN32区分不同系统,主要包括:

  1. 设备的标识,Windows下以盘符(E:\,F:\等)作为标识,Linux下则以设备路径(/dev/sdb, /dev/sdc等)作为标识。
  2. 文件路径,Windows下以反斜杠\作为分隔符,Linux下则以斜杠/作为分隔符。
  3. 和设备通信,和USB设备通信,数据层是采用SCSI协议,传输层采用的USB协议。应用软件直接采用SCSI协议与设备进行通信即可。
    a. Windows层的通信主要代码:
// Open device
char szLetter[] = "\\.\G:;
HANDLE hDev = CreateFile((LPCSTR)_devFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// Transport CMD to device
if (!DeviceIoControl(hDev,IOCTL_SCSI_PASS_THROUGH,pt,sizeof(buf),buf,sizeof(buf),&bytes,NULL)) {printf("IOCTL failed %d\n", GetLastError());}// Close device
CloseHandle(hDev);

b. Linux下通信的主要代码:

// Open device
int fd = open("/dev/sde", O_RDWR);// Transport CMD
unsigned char buff[1024] = {0};
unsigned char inq_cmd[] = {WRITE_10, 00, 0, 0, 0, 0, 0, 0, 0x2, 0};
unsigned char sense[32] = {0};
struct sg_io_hdr io_hdr = {};
io_hdr.interface_id = 'S';
io_hdr.cmdp = inq_cmd;
io_hdr.cmd_len = sizeof(inq_cmd);
io_hdr.dxferp = buff;
io_hdr.dxfer_len = 32;
io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
io_hdr.sbp = sense;
io_hdr.mx_sb_len = sizeof(sense);
io_hdr.timeout = 5000;
ioctl(fd, SG_IO, &io_hdr);// Close device
close(fd);

3.2.2. eMMC/UFS

eMMC/UFS主要用于手机、平板和一些嵌入式设备,手机和平板基本是Andriod系统,嵌入式也多是Andriod和Linux。而Andriod的内核也基本上就是Linux内核了。Andriod因为安全机制,不允许应用程序直接与存储储备通信,所有的数据传输都是加密的,所以Andriod也不方便通过应用程序来进行升级固件。
无论是Andriod还是嵌入式Linux,都是通过u-boot来启动系统的。u-boot中都已经携带有eMMC/UFS的驱动代码,并且u-boot中都会初始化eMMC/UFS,然后读取存放在eMMC/UFS上的系统进行引导启动。所以在u-boot中进行固件升级,不仅可以绕开Andriod的安全机制,升级方式也可以与Linux统一。
eMMC自从协议4.0版之后,协议提出统一的固件更新规则FFU(Field Firmware Update,现场固件更新)。其基本流程为Host发送命令进入FFU模式,通过写命令将固件bin文件写入设备存储在NAND Flash相应位置,然后Host发送激活命令、或硬件复位或者断上电操作,就可以完成固件更新。
其协议流程为:
在这里插入图片描述在这里插入图片描述

u-boot流程,修改完u-boot之后,编译成二进制文件,然后与Andriod文件一起推送到手机终端,等待用户升级系统过程中,先完成对eMMC/UFS的升级。

// 在mmc_inti之后执行如下流程
mmc_set_clock(mmc, mmc->tran_speed,MMC_CLK_ENABLE);
mmc_switch(mmc, FFU_MODE);
mmc_write(mmc, addr, buff, size);
mmc_switch(mmc, NORMAL_MODE);
mmc_power_cycle(mmc);

UFS协议继承了eMMC的FFU,其流程基本一样,只不过在激活新固件时,简化了eMMC原有的方式,只支持HW Reset或Power Cycle。
在这里插入图片描述

3.2.3. SATA SSD

SATA接口的SSD主要用于个人电脑。如果SSD作为电脑的从盘(非操作系统盘),则可以直接使用系统软件。如果SSD作为电脑的主盘(操作系统盘),由于操作系统的限制,无法直接与主盘通信。操作系统有MAC、Windows、Linux等,而且cpu内核也有x86/x86-64/Arm等,如果要编译系统软件,会有很多版本。有没有一种通用的方法兼容所有情况呢?
为了解决主盘无法直接升级,需要另外接入系统,让主盘作为从盘。

3.2.3.1. UEFI应用

当前电脑系统的启动都是通过UEFI来引导启动操作系统的,可以考虑编写UEFI应用程序,通过UEFI程序来完成对SSD固件的更新。

3.2.3.2. WinPE应用

现在安装系统,都是使用U盘来完成系统,先在U盘中安装一个Win PE的启动系统来引导安装操作系统。Win PE是一个简化版的Windows系统,可以运行基本的Windows应用程序。这种方式可以不用管电脑原来是什么操作系统,只需要针对不同CPU制作不同的Win PE启动盘即可。
● 升级工具:
SATA接口的SSD使用ATA协议来通信,并且兼容SCSI的通用命令。
可以通过SCSI的3种操作码,来配置3种ATA通信协议。

主要通信代码:

SCSI_PASS_THROUGH spt = {0};
spt.Length = sizeof(SCSI_PASS_THROUGH);
spt.TimeOutValue = 2;
spt.CdbLength = 12; // 16,32
spt.Cdb[0] = 0xA1;  // 0x85,0x7F
spt.Cdb[1] = 3 << 1;
memcpy(&spt.Cdb[3], aptex.CurrentTaskFile, 8);
ret = DeviceIoControl(handle, IOCTL_SCSI_PASS_THROUGH,&spt, sizeof(SCSI_PASS_THROUGH), NULL, 0, &nRet, NULL);
也可以直接通过ATA协议来与设备通信,其主要代码:
ATA_PASS_THROUGH_EX aptex = {0};
aptex.Length = sizeof(ATA_PASS_THROUGH_EX);
aptex.TimeOutValue = 2;
aptex.CurrentTaskFile[6] = 0xEF;
aptex.CurrentTaskFile[0] = 0x05;
aptex.CurrentTaskFile[1] = 0x80;
ret = DeviceIoControl(handle, IOCTL_ATA_PASS_THROUGH, &aptex, sizeof(ATA_PASS_THROUGH_EX), NULL, 0, &nRet, NULL);

● WinPE系统盘

  1. 制作WinPE需要安装ADK,不同版本WinPE对应不同的ADK,下载合适的ADK版本安装。
  2. 以管理员身份启动“部署和映像工具环境” 。
  3. 运行“copype”以创建 Windows PE 文件的工作副本。
    // 提取64位的WinPE资源文件
    copype amd64 C:\WinPE_amd64
    // 提取32位的WinPE资源文件
    copype x86 C:\WinPE_x86
  4. 提取镜像中文件
  5. 在WinPE中添加固件更新工具。
    把fw_update_tool.exe放在mout\Program Files目录。
  6. 启动WinPE之后自动执行升级工具。
    wpeinit
    cd …
    cd “Program Files\FWupdateTool”
    FWupdateTool.exe
  7. 提交修改
    将相关的修改提交到新的winpe.wim中,并卸载所有提取的文件。
    Dism /unmount-Wim /MountDir:C:\winpe_x86\mount /Commit
  8. 拷贝Winpe.wim至IOS目录
    copy winpe.wim C:\winpe_x86\ISO\sources\boot.wim /y
  9. 生成镜像文件
    oscdimg -n -bC:\winpe_x86\etfsboot.com C:\winpe_x86\iso C:\winpe.iso
  10. 利用Ultraiso写入镜像
    利用Ultraiso打开Winpe.iso,然后菜单选择启动->写入硬盘映像,选择指定U盘,点击确认,等待完成,winpe启动盘即制作完成。
    也可以使用命令行制作WinPE系统:
set PEPath=C:\win10PE_x86
call "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
if exist %PEPath%  rmdir /s /q %PEPath%
call CopyPE.cmd x86 %PEPath%
Dism /Mount-Image /ImageFile:%PEPath%\media\sources\boot.wim /index:1 /MountDir:%PEPath%\mount
pause
Dism /Unmount-Image /MountDir:%PEPath%\mount /commit
rem MakeWinPEMedia /ISO %PEPath% %PEPath%\Win10PE_x86.ISO
MakeWinPEMedia /ufd %PEPath% g:

3.2.4. PCIe SSD

PCIe接口的SSD主要用高性能场景,如高价个人电脑,还有云存储、企业分布式存储等。PCIe接口的SSD采用NVMe通信协议,协议中也有规定固件升级流程,和FFU流程大同小异,下载固件,激活固件。
● Windows下的实现流程:

BOOL DeviceStorageFirmwareUpgrade(int _nPhyNo, BYTE _slotID)
{QString strDeviceName = QString("%1%2").arg("\\\\.\\Physicaldrive").arg(_nPhyNo);HANDLE deviceHandle = CreateFile(strDeviceName.toStdWString().data(),GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,nullptr,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,nullptr);if (deviceHandle == INVALID_HANDLE_VALUE){return  FALSE;}// Setup header of firmware download data structure.const DWORD dwBuffSize = FIELD_OFFSET(STORAGE_HW_FIRMWARE_DOWNLOAD, ImageBuffer) + 4*1024;QScopedPointer<char> scopeBuff(new char[dwBuffSize]());PSTORAGE_HW_FIRMWARE_DOWNLOAD firmwareDownload = reinterpret_cast<PSTORAGE_HW_FIRMWARE_DOWNLOAD>(scopeBuff.get());firmwareDownload->Version = sizeof(STORAGE_HW_FIRMWARE_DOWNLOAD);firmwareDownload->Size = dwBuffSize;firmwareDownload->Flags = STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER;firmwareDownload->Slot = 0x11;// Open image file and download it to controller.ULONGLONG imageBufferLength = dwBuffSize - FIELD_OFFSET(STORAGE_HW_FIRMWARE_DOWNLOAD, ImageBuffer);QString strFilePath = ":/libra_cpu01_sysfw.bin";QFile file(strFilePath);if (!file.open(QIODevice::ReadOnly)){qDebug()<<"Open "<<strFilePath<<" failed.";return  FALSE;}ULONG imageOffset = 0;BOOL moreToDownload = TRUE;while (moreToDownload){RtlZeroMemory(firmwareDownload->ImageBuffer, imageBufferLength);qint64 readLength = file.read(reinterpret_cast<char*>(firmwareDownload->ImageBuffer), static_cast<qint64>(imageBufferLength));if (readLength == 0){file.close();break;}firmwareDownload->Offset = imageOffset;firmwareDownload->BufferSize = min(imageBufferLength, static_cast<ULONG>(readLength));ULONG returnedLength = 0;BOOL result = DeviceIoControl(deviceHandle,IOCTL_STORAGE_FIRMWARE_DOWNLOAD,scopeBuff.get(),dwBuffSize,scopeBuff.get(),dwBuffSize,&returnedLength,nullptr);if (!result){return FALSE;}imageOffset += static_cast<ULONG>(firmwareDownload->BufferSize);}// Activate the newly downloaded image.RtlZeroMemory(scopeBuff.get(), dwBuffSize);PSTORAGE_HW_FIRMWARE_ACTIVATE firmwareActivate = reinterpret_cast<PSTORAGE_HW_FIRMWARE_ACTIVATE>(scopeBuff.get());firmwareActivate->Version = sizeof(STORAGE_HW_FIRMWARE_ACTIVATE);firmwareActivate->Size = sizeof(STORAGE_HW_FIRMWARE_ACTIVATE);firmwareActivate->Slot = _slotID;firmwareActivate->Flags = STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER;// activate firmwareULONG returnedLength = 0;BOOL result = DeviceIoControl(deviceHandle,IOCTL_STORAGE_FIRMWARE_ACTIVATE,scopeBuff.get(),dwBuffSize,scopeBuff.get(),dwBuffSize,&returnedLength,nullptr);return result;
}

● Linux下有开源工具NVME-cli,可以直接使用:

> nvme fw-download /dev/nvme0 -f allBinary.bin nvme fw-commit /dev/nvme0
> -s 2 -a 1
> # 参数-s代表slot。标准定义SSD支持7个slot,slot 1 是只读权限,用于存放出厂固件,slot 2和3 可用于固件下载。
> # 参数-a代表不同的升级方法,常用的有两个。001b(向指定slot下载固件,需要reset后完成激活操作);
> # 011b(向指定slot下载固件,激活立即生效,固件升级完成)

4. 参考资料

  1. NVM Express TM Revision 1.4
  2. Information technology -SCSI / ATA Translation - 5 (SAT-5)
  3. ATA Command Pass-Through
  4. Universal Serial Bus Mass Storage Class UFI Command Specification
  5. Universal Flash Storage (UFS)Version 3.1
  6. Embedded Multi-Media Card (e•MMC) Electrical Standard (5.1)
  7. https://github.com/linux-nvme/nvme-cli/
  8. https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-ioctl_storage_firmware_activate
  9. https://learn.microsoft.com/zh-cn/windows-hardware/manufacture/desktop/winpe-intro?view=windows-11
  10. https://github.com/u-boot/u-boot

相关文章:

固态存储设备固件升级方案

1. 前言 随着数字化时代的发展&#xff0c;数字数据的量越来越大&#xff0c;相应的数据存储的需求也越来越大&#xff0c;存储设备产业也是蓬勃发展。存储设备产业中&#xff0c;发展最为迅猛的则是固态存储(Solid State Storage&#xff0c;SSS)。数字化时代&#xff0c;海量…...

Python交通标志识别基于卷积神经网络的保姆级教程(Tensorflow)

项目介绍 TensorFlow2.X 搭建卷积神经网络&#xff08;CNN&#xff09;&#xff0c;实现交通标志识别。搭建的卷积神经网络是类似VGG的结构(卷积层与池化层反复堆叠&#xff0c;然后经过全连接层&#xff0c;最后用softmax映射为每个类别的概率&#xff0c;概率最大的即为识别…...

基于Selenium+Python的web自动化测试框架(附框架源码+项目实战)

目录 一、什么是Selenium&#xff1f; 二、自动化测试框架 三、自动化框架的设计和实现 四、需要改进的模块 五、总结 总结感谢每一个认真阅读我文章的人&#xff01;&#xff01;&#xff01; 重点&#xff1a;配套学习资料和视频教学 一、什么是Selenium&#xff1f; …...

Python进阶-----高阶函数zip() 函数

目录 前言&#xff1a; zip() 函数简介 运作过程&#xff1a; 应用实例 1.有序序列结合 2.无序序列结合 3.长度不统一的情况 前言&#xff1a; 家人们&#xff0c;看到标题应该都不陌生了吧&#xff0c;我们都知道压缩包文件的后缀就是zip的&#xff0c;当然还有r…...

win10打印机拒绝访问解决方法

一直以来,在安装使用共享打印机打印一些文件的时候&#xff0c;会遇到错误提示&#xff1a;“无法访问.你可能没有权限使用网络资源。请与这台服务器的管理员联系”的问题&#xff0c;那为什么共享打印机拒绝访问呢&#xff1f;别着急&#xff0c;下面为大家带来相关的解决方法…...

深度学习训练营之数据增强

深度学习训练营学习内容原文链接环境介绍前置工作设置GPU加载数据创建测试集数据类型查看以及数据归一化数据增强操作使用嵌入model的方法进行数据增强模型训练结果可视化自定义数据增强查看数据增强后的图片学习内容 在深度学习当中,由于准备数据集本身是一件十分复杂的过程,…...

Tomcat安装及启动

日升时奋斗&#xff0c;日落时自省 目录 1、Tomcat下载 2、JDK安装及配置环境 3、Tomcat配置环境 4、启动Tomcat 5、部署演示 1、Tomcat下载 直接入主题&#xff0c;下载Tomcat 首先就是别下错了&#xff0c;直接找官方如何看是不是广告&#xff0c;或者造假 搜索Tomc…...

【专项训练】排序算法

排序算法 非比较类的排序,基本上就是放在一个数组里面,统计每个数出现的次序 最重要的排序是比较类排序! O(nlogn)的3个排序,必须要会!即:堆排序、快速排序、归并排序! 快速排序:分治 经典快排 def quickSort1(arr...

Android压测测试事件行为参数对照表

执行参数参数说明颗粒度指标基础参数--throttle <ms> 用于指定用户操作间的时延。 -s 随机数种子&#xff0c;用于指定伪随机数生成器的seed值&#xff0c;如果seed值相同&#xff0c;则产生的时间序列也相同。多用于重测、复现问题。 -v 指定输出日志的级别&#xff0c;…...

【观察】亚信科技:“飞轮效应”背后的数智化创新“延长线”

著名管理学家吉姆柯林斯在《从优秀到卓越》一书中提出“飞轮效应”&#xff0c;它指的是为了使静止的飞轮转动起来&#xff0c;一开始必须使很大的力气&#xff0c;每转一圈都很费力&#xff0c;但达到某一临界点后&#xff0c;飞轮的重力和冲力就会成为推动力的一部分&#xf…...

QT编程从入门到精通之十四:“第五章:Qt GUI应用程序设计”之“5.1 UI文件设计与运行机制”之“5.1.1 项目文件组成”

目录 第五章:Qt GUI应用程序设计 5.1 UI文件设计与运行机制 5.1.1 项目文件组成 第五章:Qt GUI应用程序设计...

(二分)730. 机器人跳跃问题

目录 题目链接 一些话 切入点 流程 套路 ac代码 题目链接 AcWing 730. 机器人跳跃问题 - AcWing 一些话 // 向上取整 mid的表示要写成l r 1 >> 1即可&#xff0c;向下取整 mid l r >> 1 // 这里我用了浮点二分&#xff0c;mid (l r) / 2&#xff0c;最…...

vue3使用nextTick

发现nextTick必须放在修改一个响应式数据之后&#xff0c;才会在onUpdated之后被调用&#xff0c;如果nextTick是放在所有对响应式数据修改之前&#xff0c;则nextTick里面的回调函数会在onBeforeUpdate方法执行前就被调用了。可是nextTick必须等到onUpdated执行完成之后执行&a…...

传统图像处理之颜色特征

博主简介 博主是一名大二学生&#xff0c;主攻人工智能研究。感谢让我们在CSDN相遇&#xff0c;博主致力于在这里分享关于人工智能&#xff0c;c&#xff0c;Python&#xff0c;爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主&#xff0c;博主会继续更新的&#xff0c…...

GPS问题调试—MobileLog中有关GPS关键LOG的释义

GPS问题调试—MobileLog中有关GPS关键LOG的释义 [DESCRIPTION] 在mobile log中,有很多GPS相关的log出现在main log和kernel log、properties文件中,他们的意思是什么,通过这篇文档进行总结,以便在处理GPS 问题时,能够根据这些log快速的收敛问题。 [SOLUTION] 特别先提醒…...

【企业管理】你真的理解向下管理吗?

导读&#xff1a;拜读陈老师一篇文章《不会向下负责&#xff0c;你凭什么做管理者&#xff1f;》&#xff0c;引发不少共鸣&#xff0c;“很多管理者有一种错误的观念&#xff0c;认为管理是向下管理&#xff0c;向上负责。其实应该反过来&#xff0c;是向上管理&#xff0c;向…...

Centos7 硬盘挂载流程

1、添加硬盘到Linux&#xff0c;添加后重启系统2、查看添加的硬盘&#xff0c;lsblksdb 8:16020G 0disk3、分区fdisk /dev/sdbmnw其余默认&#xff0c;直接回车再次查看分区情况&#xff0c;lsblksdb1 8:17 0 20G 0 part4、格式化mkfs -t ext4 /dev/sdb15、挂载mkdir /home/new…...

认识vite_vue3 初始化项目到打包

从0到1创建vite_vue3的项目背景效果vite介绍&#xff08;对比和vuecli的区别&#xff09;使用npm创建vitevitevuie3创建安装antdesignvite自动按需引入&#xff08;vite亮点&#xff09;请求代理proxy打包背景 vue2在使用过程中对象的响应式不好用新增属性的使用$set才能实现效…...

【Go】cron时间格式

【Go】cron时间格式 Minutes&#xff1a;分钟&#xff0c;取值范围[0-59]&#xff0c;支持特殊字符* / , -&#xff1b;Hours&#xff1a;小时&#xff0c;取值范围[0-23]&#xff0c;支持特殊字符* / , -&#xff1b;Day of month&#xff1a;每月的第几天&#xff0c;取值范…...

leetcode 55. 跳跃游戏

给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 示例 1&#xff1a; 输入&#xff1a;nums [2,3,1,1,4] 输出&#xff1a;true 解释&#xff1a;可以先跳 1 …...

Linux:文件流指针 与 文件描述符

目录一、文件描述符二、文件流指针三、缓冲区之前讲解过了IO库函数和IO接口&#xff0c;库函数是对系统调用接口的封装&#xff0c;也就是说实际上在库函数内部是通过调用系统调用接口来完成最终功能的。 库函数通过文件流指针操作文件&#xff0c;系统调用接口通过文件描述符操…...

基于FPGA实现正弦插值算法

1、正弦插值的算法分析 1.1 信号在时域与频域的映射关系 在进行正弦算法分析之前&#xff0c;我们回顾一下《数字信号处理》课程中&#xff0c;对于信号在时域与频域之间的映射关系&#xff0c;如下图。 对于上图中的原始信号x(t)&#xff0c;使用ADC对信号进行采样&#xff0…...

JavaWeb_会话技术

文章目录会话跟踪技术的概述Cookie概念Cookie工作流程Cookie基本使用发送Cookie获取CookieCookie原理分析Cookie的使用细节Cookie的存活时间Cookie存储中文SessionSession的基本使用概念工作流程Session的基本使用Session的原理分析Session的使用细节Session的钝化与活化Sessio…...

Reactor响应式流的核心机制——背压机制

响应式流是什么&#xff1f; 响应式流旨在为无阻塞异步流处理提供一个标准。它旨在解决处理元素流的问题——如何将元素流从发布者传递到订阅者&#xff0c;而不需要发布者阻塞&#xff0c;或订阅者有无限制的缓冲区或丢弃。 响应式流模型存在两种基本的实现机制。一种就是传统…...

[数据结构]栈的深入学习-java实现

CSDN的各位uu们你们好,今天千泽带来了栈的深入学习,我们会简单的用代码实现一下栈, 接下来让我们一起进入栈的神奇小世界吧!0.速览文章一、栈的定义1. 栈的概念2. 栈的图解二、栈的模拟实现三.栈的经典使用场景-逆波兰表达式总结一、栈的定义 1. 栈的概念 栈&#xff1a;一种…...

网络编程基础

1 互联网的本质硬件设备有了操作系统&#xff0c;然后装上软件之后我们就能够正常使用了&#xff0c;然后也只能自己使用。像这样&#xff0c;每个人都拥有一台自己的机器&#xff0c;然而彼此孤立。如何才能和大家一起愉快的玩耍&#xff1f;什么是网络&#xff1f;简单来说&a…...

华为OD机试题 - 数列还原(JavaScript)| 机考必刷

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:数列还原题目输入输出示例一输入输出Code代码解析版权说明华为O…...

10-Oracle存储过程(创建,修改,使用及管理)

本章内容 1、我们为什么要用存储过程? 2、存储过程是如何定义和维护的? 3、我们如何调用存储过程? 4、存储过程中常用的复合数据处理方式及CTE 5、存储过程如何进行异常处理? 6、存储过程如何进行事务处理? 7、我们应如何优化存储过程? 1、我们为什么要用存储过程…...

创建线程的三种方法

文章目录1、创建一个类实现Runnable接口&#xff0c;并重写run方法。2、创建一个类继承Thread类&#xff0c;并重写run方法。3、实现Callable接口&#xff0c;重写call()方法&#xff0c;这种方式可以通过FutureTask获取任务执行的返回值。4、run()方法和start()方法有什么区别…...

第一章---Pytorch快速入门---第三节---pytorch中的数据操作和预处理

目录 1.高维数组 1.1 回归数据准备 1.2 分类数据准备 2. 图像数据 1.torchvision.datasets模块导入数据并预处理 2.从文件夹中导入数据并进行预处理 pytorch中torch.utils.data模块包含着一些常用的数据预处理的操作&#xff0c;主要用于数据的读取、切分、准备等。 常用…...

【代码随想录训练营】【Day38】第九章|动态规划|理论基础|509. 斐波那契数|70. 爬楼梯|746. 使用最小花费爬楼梯

理论基础 动态规划与贪心的区别并不是学习动态规划所必须了解的&#xff0c;所以并不重要。 想要了解动态规划算法题的特点&#xff0c;可以直接做下面三道入门简单题练练手感&#xff0c;找找感觉&#xff0c;很快就能体会到动态规划的解题思想。 总结成一句话就是&#xf…...

华为OD机试题 - 快递货车(JavaScript)| 机考必刷

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:快递货车题目输入输出示例一输入输出Code解题思路版权说明华为O…...

前端——7.图像标签和路径

这篇文章&#xff0c;我们来讲解一下图像标签 目录 1.图像标签 1.1介绍 1.2实际展示 1.3图像标签的属性 1.3.1 alt属性 1.3.2 title属性 1.3.3 width / height 属性 1.3.4 border属性 1.4注意事项 2.文件夹 2.1目录文件夹和根目录 2.2 VSCode打开目录文件夹 3.路…...

java -- stream流

写在前面: stream流一直在使用&#xff0c;但是感觉还不够精通&#xff0c;现在深入研究一下。 stream这个章节中&#xff0c;会用到 函数式接口–lambda表达式–方法引用的相关知识 介绍 是jdk8引进的新特性。 stream流是类似一条流水线一样的操作&#xff0c;每次对数据进…...

【Spring6】| Bean的四种获取方式(实例化)

目录 一&#xff1a;Bean的实例化方式 1. 通过构造方法实例化 2. 通过简单工厂模式实例化 3. 通过factory-bean实例化 4. 通过FactoryBean接口实例化 5. BeanFactory和FactoryBean的区别&#xff08;面试题&#xff09; 6. 使用FactoryBean注入自定义Date 一&#xff1a…...

01: 新手学SpringCloud前需知道的5点

目录 第一点&#xff1a; 什么是微服务架构 第二点&#xff1a;为什么需要学习Spring Cloud 第三点&#xff1a; Spring Cloud 是什么 第四点&#xff1a; SpringCloud的优缺点 1、SpringCloud优点 2、SpringCloud缺点 第五点&#xff1a; SpringCloud由什么组成 1&…...

ubuntu apt安装arm交叉编译工具

查找查找编译目标为32位的gcc-arm交叉编译器命令apt-cache search arm|awk index($1,"arm")!0 {print}|grep gcc-arm\|g-arm #或者 apt-cache search arm|awk index($1,"arm")!0 {print}|grep -E gcc-arm|g\\-arm输出如下g-arm-linux-gnueabihf - GNU C co…...

阿里云一面经历

文章目录 ES 查询方式都有哪些?1 基于词项的查询term & terms 查询Fuzzy QueryWildcard Query2 基于全文的查询Match QueryQuery String QueryMatch Phrase Query3 复合查询Bool QueryElasticsearch 删除原理ES 大文章怎么存arthas 常用命令arthas 排查问题过程arthas 工作…...

Java Stream中 用List集合统计 求和 最大值 最小值 平均值

对集合数据的统计&#xff0c;是开发中常用的功能&#xff0c;掌握好Java Stream提供的方法&#xff0c;避免自己写代码统计&#xff0c;可以提高工作效率。 先造点数据&#xff1a; pigs.add(new Pig(1, "猪爸爸", 31, "M", false)); pigs.add(new Pig(…...

【Linux】多线程---线程控制

进程在前面已经讲过了&#xff0c;所以这次我们来讨论一下多线程。前言&#xff1a;线程的背景进程是Linux中资源及事物管理的基本单位&#xff0c;是系统进行资源分配和调度的一个独立单位。但是实现进程间通信需要借助操作系统中专门的通信机制&#xff0c;但是只这些机制将占…...

秒杀高并发解决方案

秒杀高并发解决方案 1.秒杀/高并发方案-介绍 秒杀/高并发 其实主要解决两个问题&#xff0c;一个是并发读&#xff0c;一个是并发写并发读的核心优化理念是尽量减少用户到 DB 来"读"数据&#xff0c;或者让他们读更少的数据, 并 发写的处理原则也一样针对秒杀系统需…...

【每日一题】蓝桥杯加练 | Day07

文章目录一、三角回文数1、问题描述2、解题思路3、AC代码一、三角回文数 原题链接&#xff1a;三角回文数 1、问题描述 对于正整数 n, 如果存在正整数 k 使得n123⋯k k(k1)2\frac{k(k1)}{2}2k(k1)​ , 则 n 称为三角数。例如, 66066 是一个三角数, 因为 66066123⋯363 。 如果一…...

条件语句(分支语句)——“Python”

各位CSDN的uu们你们好呀&#xff0c;最近总是感觉特别特别忙&#xff0c;但是却又不知道到底干了些什么&#xff0c;好像啥也没有做&#xff0c;还忙得莫名其妙&#xff0c;言归正传&#xff0c;今天&#xff0c;小雅兰的内容还是Python呀&#xff0c;介绍一些顺序结构的知识点…...

论文投稿指南——中文核心期刊推荐(国家财政)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…...

面向数据安全共享的联邦学习研究综述

开放隐私计算 摘 要&#xff1a;跨部门、跨地域、跨系统间的数据共享是充分发挥分布式数据价值的有效途径&#xff0c;但是现阶段日益严峻的数据安全威胁和严格的法律法规对数据共享造成了诸多挑战。联邦学习可以联合多个用户在不传输本地数据的情况下协同训练机器学习模型&am…...

Redis经典五种数据类型底层实现原理解析

目录总纲redis的k,v键值对新的三大类型五种经典数据类型redisObject结构图示结构讲解数据类型与数据结构关系图示string数据类型三大编码格式SDS详解代码结构为什么要重新设计源码解析三大编码格式hash数据类型ziplist和hashtable编码格式ziplist详解结构剖析ziplist的优势(为什…...

Jackson 返回前端的 Response结果字段大小问题

目录 1、问题产生的背景 2、出现的现象 3、解决方案 4、成果展现 5、总结 6、参考文章 1、问题产生的背景 因为本人最近工作相关的对接外部项目&#xff0c;在我们国内有很多程序员都是使用汉语拼音或者部分字母加上英文复合体定义返回实体VO&#xff0c;这样为了能够符合…...

每天五分钟机器学习:你理解贝叶斯公式吗?

本文重点 贝叶斯算法是机器学习算法中非常经典的算法,也是非常古老的一个算法,但是它至今仍然发挥着重大的作用,本节课程及其以后的专栏将会对贝叶斯算法来做一个简单的介绍。 贝叶斯公式 贝叶斯公式是由联合概率推导而来 其中p(Y|X)称为后验概率,P(Y)称为先验概率…...

C++的入门

C的关键字 C总计63个关键字&#xff0c;C语言32个关键字 命名空间 我们C的就是建立在C语言之上&#xff0c;但是是高于C语言的&#xff0c;将C语言的不足都弥补上了&#xff0c;而命名空间就是为了弥补C语言的不足。 看一下这个例子。在C语言中会报错 #include<stdio.h>…...

数据的存储

类型的意义&#xff1a;使用这个类型开辟内存空间的大小&#xff08;大小决定了使用范围&#xff09;如何看待内存空间视角类型的基本归类整型家族浮点数家族构造类型指针类型空类型整型存储解构:整型在计算机中占用四个字节&#xff0c;整型分为无符号整型和有符号整型在计算机…...