linux 启动过程 GRUB 引导流程

news/2024/11/6 11:09:06/文章来源:https://www.cnblogs.com/rebrobot/p/18525360

 

https://www.cnblogs.com/Link-Luck/p/9858519.html

Boot loader引导加载器,用来引导系统的启动,它把用户选定的内核加载到内存空间中,把控制权交给内核。
  Windows下引导加载器:ntloader
  Linux下引导加载器:
    LILO:LInux LOader
    GRUB:GRand Unified Bootloader
      GRUB Legacy 0.X 传统版本为0.X
      GRUB2    1.X 与传统版本完全不一样的1.X版本
    功能:提供一个菜单,允许用户选择要启动的系统或内核版本;把用户选定内核装载到RAM的特定空间中并解压展开,而后把系统控制权移交给内核;
    MBR所给予的空间毕竟太小,容不下较大的引导程序,因此grub程序被分为三段:"stage 1" 被装入磁盘的MBR中;特殊的"stage 1.5"被装入MBR随后的扇区,它能够识别内核和"stage 2"所在分区的文件系统格式并帮助引导"stage 2",它是"stage 1"和"stage 2"之间的纽带;"stage 2"位于文件系统上。stage 2程序和grub.conf可以与内核文件处于不同的分区上(但必须位于同一磁盘),只要"stage 1.5"能够驱动它们各自所在的分区。
    GRUB引导过程分为三段:
      stage1:MBR(0柱面0磁道1扇区)
      stage1_5:MBR随后的扇区
      stage2:读取grub.conf配置文件,并实现引导功能的扩展

  Kernel:加载系统内核,执行系统初始化信息
  在GRUB中选定内核进入,内核会对自身初始化;探测可识别到的所有硬件设备,加载硬件驱动程序(有可能需要借助ramdisk加载驱动);以只读方式挂载根文件系统;运行用户空间的第一个应用程序:/sbin/init
 Centos5:initrd
  initrd文件生成工具程序:mkinitrd
  Centos6,7:initramfs(cpio格式)
  initramfs文件生成工具程序:dracut、mkinitrd

 ramdisk:Linux内核的特性之一,使用缓冲和缓存来加速对磁盘上的文件访问:
  为什么将initrd改为initramfs,前者把内存模拟成磁盘,后者直接把内存模拟成文件系统;如果模拟成磁盘,将磁盘加载到内存中,内核需将initrd再次缓存到内核的内存空间当中,相当于在内存中缓存两次;但是如果模拟成文件系统,内核可以直接访问文件系统所在的内存空间,这样效率更高性能更好
  initrd 、initramfs都属虚拟文件系统,在早期的linux系统中,一般只有硬盘或者软盘被用来作为Linux根文件系统的存储设备,因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的Linux系统中可能将根文件系统保存到各种存储设备上,包括scsi、sata,usb-disk等等。如果把这些设备的驱动代码全部编译到内核中内核会很庞大。
  为了解决这一矛盾,于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中必须的驱动模块、可执行文件和启动脚本。当系统启动的时候bootloader会把initrd文件读到内存中,然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,并执行根目录中的/linuxrc脚本(cpio格式的initramfs为/init,而image格式的initrd为/linuxrc),脚本会加载真实文件系统中存放的设备驱动程序,以及在/dev目录下创建必要的设备节点。这样就可以mount真正的根目录,并切换到这个根目录中。

  Linux 发行版在内核中只编译了基本的硬件驱动,在Linux系统安装过程中通过检测系统硬件,生成包含安装系统硬件驱动的initrd,在内核引导过程中先加载initrd虚拟文件系统,然后由initrd挂载真正的文件系统,完成后initrd从RAM中退出,并不消耗内存,initrd只是一个暂时的文件系统。
  在Linux2.5内核中出现了initramfs,它的作用和initrd类似,只是和内核编译成一个文件(initramfs是经过gzip压缩后的cpio格式文件),该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs上,其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压,然后使用它作为临时的根文件系统。

  initrd与initramfs的区别:
  initrd是init ram disk,initramfs是init ram file system,前者把内存模拟成磁盘,后者直接把内存模拟成文件系统
  cpio-initrd(initramfs)的处理流程
    1、boot loader 把内核以及 initrd 文件加载到内存的特定位置
    2、内核判断initrd的文件格式,如果是cpio格式
    3、将initrd的内容解压到rootfs中
    4、执行initrd中的/init文件,切换到真实的根文件系统,执行/sbin/init
  image-initrd(initrd)的处理流程
    1、boot loader把内核以及initrd文件加载到内存的特定位置。
    2、内核判断initrd的文件格式,如果不是cpio格式,将其作为image-initrd处理。
    3、内核将initrd的内容保存在rootfs下的/initrd.image文件中。
    4、内核将/initrd.image的内容读入/dev/ram0设备中,也就是读入到一个内存盘中。
    5、接着内核以可读写的方式把/dev/ram0设备挂载为原始的根文件系统。
    6、如果/dev/ram0被指定为真正的根文件系统,那么内核跳至最后一步正常启动。
    7、执行initrd上的/linuxrc文件,linuxrc通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动, 以及加载根文件系统。
    8、/linuxrc执行完毕,真实的根文件系统被挂载
    9、如果真实根文件系统存在/initrd目录,那么将/dev/ram0从/移动到/initrd;如果不存在/initrd目录,/dev/ram0将被卸载。
    10、在真实根文件系统上进行正常启动过程 ,执行/sbin/init。

 

https://www.cnblogs.com/Link-Luck/p/9858869.html

 

GRUB(bootloader)引导流程:
  GRUB,GRand Unified Bootlader ,是一个来自GUN项目的多操作系统启动程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。
  grub版本:
  grub 0.x:grub(legacy) Centos 5,6
  grub 1.x:grub2     Centos 7

  grub legacy版本:
  工作流程:当系统启动时,如果要加载grub所在的磁盘时,会读取这个磁盘的MBR,同时会加载stage1,stage1会尝试读取后扇区的stage1_5阶段,stage1_5阶段会帮助stage1中的bootloader识别stage2所在的分区上的文件系统,然后加载stage2所在的磁盘分区,这个分区不但有stage2阶段,还有内核和ramdisk等。

  stage1:运行Boot Loader主程序,这个程序必须要安装在启动区,即MBR中。因为MBR空间有限,因此在MBR当中仅安装Boot Loader的最小程序,并没有安装Boot Loader的相关配置文件
  stage1_5:MBR之后的扇区,让stage1中的BootLoader能识别stage2所在的分区上的文件系统(相当于文件系统的驱动)
  stage2:boot目录所在的磁盘分区(/boot/grub)
  配置文件:/etc/grub.conf软链接到/boot/grub/grub.conf
       /boot/grub/menu.lst软链接到/boot/grub/grub.conf

 stage2及内核等通常放置于一个基本磁盘分区(boot分区)
  boot单独分区是用来存放与Linux系统启动有关的程序,比如内核文件、启动引导装载程序,启动菜单配置文件等;
  boot作为一个单独的分区,也就意味着这个单独分区下有一个grub,因为grub刚启动的时候,操作系统还没有启动(真正的根文件系统还没有被加载),所以,不能通过访问/boot/grub来实现,但是我们又需要访问这个文件来执行stage2 阶段。所以,grub中就有一个root命令,指明的就是把stage2 阶段直设为根,而grub自带有文件系统驱动(stage 1.5),所以就可以直接访问分区及根下的所有文件即kernel,initrd等来选择内核启动;
  boot目录,有没有单独分区(或者说引导分区是不是一个独立的分区),决定了在grub中的访问路径是否一样。而grub中的root命令,指明的就是这个根分区是谁,如果boot被单独分区了,那么就直接指向这个新分区,访问路径就直接把boot给去掉了;如果boot没有被单独分区,就是挂在根分区上,那就意味着/boot目录是绕不过去的,访问的时候只能先访问根,在访问根下的boot。
  grub要想访问某一分区,这个分区必须是基本磁盘分区,不可能是提供了非常复杂的驱动程序(RAID或LVM)。如果想把根做的复杂些(比如LVM)但又不对boot做单独分区,那把逻辑卷往分区上一放,就找不到grub中的stage2阶段了,所以,要想把根做的复杂,就只能把boot作为一个单独的基本磁盘分区;
  如果不使用逻辑卷,boot是可以不用单独分区的。

  stage2的主要功能:
  1、提供菜单、并提供交互式接口
    e:编辑模式,用于编辑菜单
    c:命令模式,交互式接口

  2、 加载用户选择的内核或操作系统
    允许传递参数给内核
    可隐藏此菜单
  3、为菜单提供了保护机制
    为编辑菜单进行认证
    为启用内核或操作系统进行认证

  GRUB识别硬盘设备:(hd#,#)表示第几块磁盘的第几块分区
    hd# 磁盘编号用数字表示,从0开始编号
    #  分区编号用数字表示,从0开始编号
   例如(hd0,0)表示第一块硬盘的第一个分区

grub命令行接口:
  help:获取帮助列表
  help KEYWORD:查看指定命令的详细帮助信息
  find (hd#,#)/PATH/TO/SOMEFILE:查找某个磁盘上的某个文件
  root (hd#,#):设置grub的根设备(boot目录所在的磁盘设备)
  initrd /PATH/TO/INITRAMFS_FILE:设定选定内核配套的ramdisk文件
  boot:引导启动选定的内核
  kernel /PATH/TO/KERNEL_FILE:设定本次启动时用到的内核;额外还可以添加许多内核支持的cmdline参数:
  例如:init=/path/to/init, selinux=0
  内核支持的启动参数:
    磁盘相关启动参数:
    root 指定启动系统的真实根文件系统所在分区 如:root=/dev/sda1
    ro  指定根设备在启动过程中为readly-only(只读),默认情况下为ro(这里根设备指的是grub的根设备)
    rw  指定根设备在启动过程中为read-write(读写)
    rootfstype 指定根文件系统类型,如:rootfstype=ext4

    console和kernel log相关的启动参数:
    console console的设备和选项,如:console=tty0,console=ttyS0
    debug  enable kerneldebugging 系统启动中的所有debug信息
    quiet  静默模式将kernel loglevel设置为KERN_WARNING,在启动中指非常严重的信息
    loglevel 设置默认的console日志级别,如:loglevel=7(0~7数字分别为KERN_EMERG,…,KERN_DEBUG)
    time   设置在每条kernel log信息前加一个时间戳

    内存相关的启动参数:
    mem 指定kernel使用的内存量,mem=n[KMG]
    hugepages 设置大页表页(4MB大小)的最多个数,hugepages=n

    CPU启动的相关参数:
    mce     #Enable the machine check exception feature.
    nosmp   #Run as a single-processor machine. 只使用一个处理器,不使用SMP(多处理器)
    max_cpus #max_cpus=n, SMP系统最多能使用的CPU个数

    Ramdisk相关的启动参数:
    initrd  指定初始化ramdisk的位置,initrd=filename
    noinitrd 不使用initrd的配置,即使配置了initrd参数

    初始化相关启动参数:
    init 在启动时去执行的程序,init=filename,默认值为/sbin/init

    PCI相关的启动参数:
    pci #pci相关的选项,我常使用pci=assign_buses,也使用过pci=nomsi

    SELinux相关启动参数:
    enforcing #SELinux enforcing状态的开关,enforcing=0表示仅仅是记录危险 而不是阻止访问,enforcing=1完全enable,默认值是0
    selinux 在启动时关闭或开启SELinux,selinux=0表示关闭,selinux=1表示开启selinux

  手动在grub命令行启动系统:
  grub> root(hd#,#)
  grub> kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE
  grub> initrd /initramfs-VERSION-RELEASE.img
  grub> boot


配置文件:/boot/grub/grub.conf
  default=# 设定默认启动菜单项;菜单项(title)编号从0开始
  timeout=# 指定菜单项等待选择的时长
  splashimage=(hd#,#)/PATH/TO/XPM_PIC_FILE 指明菜单背景图片文件路径
  hiddenmenu 隐藏菜单,如果有多个菜单项,只显示默认启动菜单项
  password [--md5] STRING 编辑菜单项需要认证
  title TITLE 定义菜单项"标题", 可出现多次
  root (hd#,#) grub查找stage2及kernel文件所在设备分区;为grub的"根"
  kernel /PATH/TO/VMLINUZ_FILE [PARAMETERS] 启动的内核文件
  initrd /PATH/TO/INITRAMFS_FILE 与内核匹配的initramfs文件
  password [--md5] STRING 启动选定内核或操作系统时需要认证

  每行详细解释:
  default=#: 设定默认启动的菜单项;假如同时装有多个操作系统,0表示定义的第一个title系统,1表示定义的第二个title系统,以此类推
  timeout=#:表示可供选择的等待时间,如果超出5秒,则使用默认的启动条目default定义的
  splashimage=(hd#,#)/PATH/TO/XPM_FILE:菜单背景图片文件路径
  hiddenmenu:隐藏菜单,默认是不显示菜单信息,如果要想显示菜单,可以将该配置信息注释即可
  password [--md5] STRING: 启动菜单编辑认证
  title TITLE:定义菜单项“标题”(操作系统名称), 可出现多次,用来引导不同的操作系统或内核
    root (hd#,#):grub查找stage2及kernel文件所在设备分区;为grub"根"。也就是说,表示的是内核文件的存放位置,这里指的是分区位置,而非根目录
    kernel /PATH/TO/VMLINUZ_FILE [PARAMETERS]:内核的名称,以及一些启动时的核心参数。由于启动过程中需要挂载根目录,因此就需要指定根目录所在的分区。rhgb表示色彩显示,quiet表示静默模式加载内核
    initrd/PATH/TO/INITRAMFS_FILE: 内核匹配的ramfs文件,虚拟文件系统
    password [--md5] STRING: 启动选定的内核或操作系统时进行认证

grub-md5-crypt命令生成密钥:
  [root@localhost ~]# grub-md5-crypt
  Password:
  Retype password:
  $1$TcvuB$S9n4SJLUnvoM3NXYT6Fk2.
  编辑grub.conf文件将秘钥添加到相应位置vim /etc/boot/grub.conf
  passwd --md5 $1$TcvuB$S9n4SJLUnvoM3NXYT6Fk2.


实验1:为编辑启动菜单进行认证;为启用内核或操作系统进行认证
  1、复制一份内核文件,改名为Tao Linux,并分别在第一个title之前和第二个title之后添加生成的加盐密码,保存并退出,并重启系统;

  2、重启系统之后发现要为进行编辑启动菜单的认证,效果如下:

  3、按“p”键输入密码之后,可以发现原来的提示信息又回来了,这是我们就可以编辑了

 

  4、选择第二个内核作为启动程序,按回车键发现要想启动内核,要输入密码认证,说明我们为内核设置的密码,起作用了。

 


进入单用户模式:
1、编辑grub菜单(选定要编辑的title,按"e"命令进行编辑)
2、在选定的kernel后添加1, s, S或single参数都可以
3、在kernel所在行,按"b"命令启动kernel

实验2:单用户模式下修改密码
1、在进入开机界面的时候,按任意键进入菜单界面

2、因为我们在编辑启动菜单前设置了认证,所以需要输入密码,按"p"输入密码后进入编辑菜单,然后选定要启动的内核,按"e"键进入编辑模式

 

3、选定好要启动的kernel后,按"e"键进入,然后在选定的内核后添加1, s, S或single,然后按回车键,紧接着在kernel所在行输入"b"进入单用户模式


grub安装:出现grub损坏或给其它硬盘安装grub
  1、通过grub-install命令进行grub安装(这种方式二进制类的文件可以恢复,但是背景图片和grub.conf的文件不能恢复。会安装grub stage1和stage1_5到/dev/DISK磁盘上,并复制GRUB相关文件到 DIR/boot目录下(这里的DIR指的是boot目录的上一级目录)
  grub-install -root-directory=DIR /dev/sda
  2、在grub命令行进行grub安装,需要依赖/boot/grub/目录中除grub.conf之外的其它文件,这些文件都是完好存在情况下才能安装
  grub> root (hd#,#)
  grub> setup (hd#)

示例1:重新安装grub, 用grub-install安装
  1、 dd if=/dev/zero of=/dev/sda bs=200 count=1  模拟破坏掉grub的stage 1(bootloader)
  2、grub-install --root-directory=/ /dev/sda  重新安装grub


示例2:在grub命令提示符下修复grub(需要依赖/boot/grub/中的除grub.conf之外的文件都是完好情况下)
  1、dd if=/dev/zero of=/dev/sda bs=200 count=1  模拟破坏掉grub的stage 1(bootloader)
  2、grub  进入grub命令提示符下
  3、root (hd0,0)  指定grub的根所在的硬盘分区(也就是boot目录所在的硬盘分区)
  4、setup (hd0)  开始安装grup,需要指定grub所在硬盘
  5、quit命令退出grup命令行模式


示例3:在紧急救援模式下修复grub(在grub损坏情况下设备重启了,这时候肯定起不来了)
  1、dd if=/dev/zero of=/dev/sda bs=200 count=1  模拟破坏掉grub的stage 1(bootloader)
  2、reboot  重启设备加载安装光盘,进入救援模式

选择将根文件系统挂载到救援模式系统的/mnt/sysimage目录

提示挂载成功,并可以通过chroot命令切换根

启动shell

3、进入shell界面,切换根开始修复grub

总结:GRUB启动故障排除案例
  1、MBR中grub损坏,1_5阶段的数据损坏,2阶段的grub损坏
  2、initramfs*.img文件损坏,内核文件损坏
  3、/boot/grub/grub.conf文件丢失
  4、/etc/fstab丢失,无法挂载根等文件系统
  5、/boot 目录全部的文件丢失

解决方法(都是在救援模式下)
  1、MBR中grub损坏,1_5阶段的数据损坏,2阶段的grub损坏;救援模式:
    chroot /mnt/sysimage 切根,改变磁盘根目录
    grub-install /dev/sda 安装grub引导程序到磁盘/dev/sda的MBR扇区

  2、initramfs*.img文件损坏,内核文件损坏
    initramfs*.img文件损坏,解决方法:
    # chroot=/mnt/sysimage
    # mkinitrd /boot/initramfs-$(uname -r).img $(uname -r) #创建
  内核文件损坏
    # mkdir /mnt/cdrom
    # mount /dev/cdrom /mnt/cdrom 挂载光盘
    进入/mnt/cdrom/Packages/ 目录下覆盖安装kernel包,
   rpm -ivh–replacepkgs kernel-VERSION.rpm –root=/mnt/sysimage –force
    安装完成后会在/boot目录下自动生成相应版本的vmlinuz文件.(前提是内核版本未更新, 和光盘中的内核版本一致)

  3、/boot/grub/grub.conf文件丢失
    这个新建一个写上引导等信息就行

  4、/etc/fstab丢失,无法挂载根等文件系统
    同样新建一个/etc/fatab、填写上挂载信息
    LVM的话需要激活LVM逻辑卷

  5、/boot目录全部的文件丢失
    结合上面,先MBR修复,然后内核文件修复和initramfs*.img文件修复


示例4:虚拟机下手动制作grub
  1、准备好一个新硬盘,分3个分区(根分区、swap、boot)分别格式化,这里的boot单独分一个区
    /boot:mkfs.ext4 /dev/sdb1
    /:mkfs.ext4 /dev/sdb2
    swap:mkswap /dev/sdb3
  2、模拟启动时的boot目录,将其挂载到当前系统/mnt/boot/目录(创建的目录名一定要为boot)
    mkdir /mnt/boot
    mount /dev/sdb1 /mnt/boot
  3、将制作grub到新硬盘的boot分区(指定根目录就是boot目录所在的上一级目录)
    grub-install --root-directory=/mnt /dev/sdb
  4、复制当前系统的内核文件和initramfs文件到/mnt/boot/目录中,并手动创建grub.conf配置文件
    cp /boot/vmlinuz-2.6.32-573.el6.x86_64 /mnt/boot/vmlinuz
    cp /boot/initramfs-2.6.32-573.el6.x86_64.img /mnt/boot/initramfs.img
    vim /mnt/boot/grub/grub.conf
      default=0
      timeout=5
      title centos 6 (Express)
      root (hd0,0)
      kernel /vmlinuz ro root=/dev/sda2 selinux=0 init=/bin/bash
      initrd /initramfs.img
  5、为根分区创建常用的一级子目录
    mkdir /mnt/sysroot
    mount /dev/sdb2 /mnt/sysroot/
    cd /mnt/sysroot/
    mkdir -pv etc bin sbin lib lib64 dev proc sys tmp var usr home root mnt media
  6、拷贝bash程序和依赖的库文件到根文件系统上的对应目录
    cp /bin/bash /mnt/sysroot/bin/
    ldd /bin/bash  查看bash程序依赖的库文件
    cp /lib64/libtinfo.so.5 /mnt/sysroot/lib64/
    cp /lib64/libdl.so.2 /mnt/sysroot/lib64/
    cp /lib64/libc.so.6 /mnt/sysroot/lib64/
    cp /lib64/ld-linux-x86-64.so.2 /mnt/sysroot/lib64/
    sync  将内存数据同步到硬盘
  7、用新的硬盘去创建一个虚拟机,检验是否能正常启动

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Air780E之TCP应用,你了解吗?

​ 一、TCP简介 TCP(TransmissionControlProtocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它主要用于在不可靠的网络环境中提供稳定的数据传输服务,确保数据能够按照顺序、无错误地到达接收端。TCP通过三次握手建立连接,使用滑动窗口进行流…

SPI接口,如何对W25Q64进行读写操作?深度解析

​ 一、SPI概述 SPI(SerialPeripheralInterface)是一种同步串行通信协议,广泛应用于微控制器和外围设备之间的数据传输。它由摩托罗拉公司开发,具有全双工通信能力,即可以同时进行数据的发送和接收。 SPI通信通常涉及四条信号线: (1)MOSI(MasterOutSlaveIn):主设备发…

如何在Chrome最新浏览器中调用ActiveX/OCX控件?

小编最近登陆工商银行网上银行,发现工商银行的个人网银网页,由于使用了ActiveX安全控件,导致不能用高版本Chrome浏览器打开,目前只有使用IE或基于IE内核的浏览器才能正常登录网上银行,而IE已经彻底停止更新了,打开工商银行个人网银登陆页面会显示下面提示,对于用户来说非…

java通过日期获取季度的日常用法

在日常的工作当中,我们经常会遇到将日期对应通过接口返回季度的业务需求;一般的方法有如下: 第一种方式:用LocalDate/*** 根据当前日期获取季度* @param date 日期* @return 季度*/public static int getQuarterOfYear(LocalDate date) {return (int) date.get(IsoFields.Q…

dubbo3.0 服务导入导出原理

不管是服务导出还是服务引入,都发生在应用启动过程中,比如:在启动类上加上 @EnableDubbo 时,该注解上有一个 @DubboComponentScan 注解,@DubboComponentScan 注解 Import 了一个 DubboComponentScanRegistrar,DubboComponentScanRegistrar 中会调用 DubboSpringInitializ…

Oracle 12c安装图文详解!内附安装包!

首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247486652&idx=1&sn=b2e1663c3287e072192c8faa5287f6ea&chksm=ea3758ccdd40d1dafbcdc4136588f02214df324feb3228f885662c7d55a17345ec47b7626640&token…

用户行为数据集

通过百度网盘分享的文件:电商平台行为数据集.csv链接:https://pan.baidu.com/s/1gKWhhTgZOThMugq8mhvuqA?pwd=1111 提取码:1111 --来自百度网盘超级会员V4的分享

如何用猿大师办公助手实现多人同时在线编辑Office Word文档?

猿大师办公助手作为一个专业的网页在线编辑 Office 插件,集成到Web项目上非常简单,前端代码只需要简单JS调用接口就可以实现在线编辑Office的功能,还有很多用户有多人同时在线编辑Office Word文档的需求,下面介绍如何用猿大师办公助手实现多人同时在线编辑Office Word文档。…

如何在Web网页在线预览、编辑Excel表格并保存到自己服务器上?

猿大师办公助手作为一款专业级的网页编辑Office方案,不仅可以把微软Office、金山WPS和永中Office的Word文档内嵌到浏览器网页中实现在线预览、编辑保存等操作,还可以把微软Office、金山WPS和永中Office的Excel表格实现网页中在线预览、编辑并保存到服务器。 猿大师办公助手是…

小程序多端引流技术上的“降本增效”

通过小程序容器技术,电商企业可以快速实现多端引流,将流量转化为实际销售。同时,跨端框架的应用,极大地提高了技术研发效率,缩短了产品上线周期。小程序容器在端侧和智慧屏上的高效运行,进一步拓展了电商应用的场景,为消费者提供了更加便捷、个性化的购物体验。中国经济…

Sealos 基础教程:Sealos Devbox 的架构原理解析

今天这篇文章咱们来聊一聊 Sealos Devbox 到底是怎么设计的,据说隔壁老奶奶最喜欢看这种有技术深度的文章了。 Devbox 返璞归真,把开发者的开发精力放到开发中去,真正做到了摈弃复杂的 CI/CD,Docker,YAML 编排,除此之外还力求拉平开发与测试与运维团队之间的一切界限,从…

复训时很好的字符串题

descriptionsolution 考虑到这么一件事情,就是我最终的字符串 \(t\) 一定是由 \(s\) 的若干段前缀拼接而成,因为如果不是前缀,换成前缀一定不劣。 然后我们拥有一个朴素的状态 \(f_{i, j}\) 表示填到第 \(i\) 个数,且最后一段是由一段长度为 \(j\) 的前缀拼接成的最大贡献。…