QEMU开发入门

news2024/11/15 11:18:52

1. 简介

QEMU(Quick EMUlator)是一个开源的虚拟化软件,它能够模拟多种硬件平台,并在这些平台上运行各种操作系统。QEMU可以在不同的主机架构之间进行虚拟化,例如x86、ARM、PowerPC、Risc-V等。QEMU是一个功能强大且灵活的虚拟化软件,可用于多种应用场景,包括系统仿真、硬件虚拟化、交叉编译以及设备模拟等。它广泛应用于开发、测试和部署各种软件和操作系统。
以下是QEMU的一些重要特点和用途:

  1. 系统仿真:QEMU可以模拟整个计算机系统,包括处理器、内存、硬盘、网络接口等。这使得用户可以在自己的计算机上运行不同体系结构的操作系统,如在x86主机上运行ARM操作系统。
  2. 虚拟化支持:QEMU提供了硬件虚拟化功能,允许在宿主机上创建和管理虚拟机。这样可以在一台物理机上同时运行多个操作系统实例,每个实例都像独立的计算机一样运行。
  3. 交叉编译支持:QEMU可以为不同的目标平台提供交叉编译环境,以便在一种体系结构上编译代码并在另一种体系结构上执行。
  4. 快速启动时间:QEMU通过使用动态二进制翻译技术(Dynamic Binary Translation)来提高性能。它将客户机指令动态转换为主机指令,从而提供接近原生速度的执行效率。
  5. 虚拟设备模拟:QEMU提供了许多虚拟设备模拟,如磁盘驱动器、网络接口卡、显卡等。这些设备可以用于测试和开发目的,或者在虚拟机中运行嵌入式操作系统。

2. 安装

QEMU适用于Windows、Linux和Mac,因为Linux开源的原因,QEMU在Linux上能够更好地利用虚拟化等技术,使得虚拟的性能相较其他平台会更好一些。通用情况下,可以直接使用预编译后的二进制版本,如果需要进行额外地扩展,可以自行编译版本。

2.1. Windows

2.1.1. 二进制版本

● 可以从https://qemu.weilnetz.de/下载相应的版本。
● 可以在MSYS32中通过命令 pacman -S qemu 来安装。

2.1.2. 编译版本

Windows版本的QEMU需要使用mingw来编译,可以在Linux下编译,也可以在Windows下编译。Windows下推荐使用MSYS2进行编译。

  1. 从MSYS2官网下载安装最新版本。
  2. 启用MSYS2,更新最新源。

pacman -Syu

  1. 重启MSYS2,更新最新软件包。

pacman -Su

  1. 安装基本开发工具包

pacman -S base-devel mingw-w64-x86_64-toolchain git python ninja

  1. 安装QEMU相关依赖包

pacman -S mingw-w64-x86_64-glib2 mingw-w64-x86_64-pixman python-setuptools

  1. 添加扩展特性依赖包

pacman -S mingw-w64-x86_64-gtk3 mingw-w64-x86_64-SDL2 mingw-w64-x86_64-libslirp

  1. 关闭MSYS2控制台。
  2. 启动msys目录下的mingw64.exe。
  3. 下载最新的QEMU源代码

git clone https://gitlab.com/qemu-project/qemu.git
// gitlab较慢时,可以使用国内镜像
git clone https://gitee.com/mirrors/qemu.git

  1. 编译

cd qemu
./configure
make

更多编译方法参见:QEMU Build for Windows

2.2. Linux

此处主要以ubuntu 22.04版本为例。

2.2.1. 二进制版本

Linux下的qemu各版本需要分别安装,如:

sudo apt install qemu-system-arm
sudo apt install qemu-system-aarch64
sudo apt install qemu-system-riscv32
sudo apt install qemu-system-riscv64

2.2.2. 编译安装

推荐从源码编译安装,更方便调试添加打印信息。推荐以tag版本安装,更可靠。以下测试是基于从gitee上克隆的版本进行测试。安装可以配置–enable-debug启用调试。

git clone https://gitee.com/mirrors/qemu.git
cd qemu
mkdir build
cd build
…/configure
make -j8
sudo make install

2.2.3. 测试

输入qemu-system-aarch64 -version显示以下信息表示安装成功。

QEMU emulator version 8.1.93 (v8.2.0-rc3)
Copyright © 2003-2023 Fabrice Bellard and the QEMU Project developers

3. 使用

3.1. 嵌入式裸机

此处以最小系统嵌入式固件来演示使用过程,并且分别演示Windows和Linux下的交叉编译,以及基于Cortext-M和risc-v两个当下流行的单片机为例。代码只执行一个Uart打印信息。

int main (void)
{
    InitUart();
    UartWrite("Hello World!\n", 13);
    while (1)
    {
        /* code */
    }

    return 0;
}

3.1.1. Cortex-M7

  1. 下载交叉编译工具,https://developer.arm.com/downloads/-/gnu-rm
  2. 将工具目录(如D:/toolchains/arm/arm-eabi-v103/bin)添加进环境目录。
  3. 进入代码目录,以make编译生成elf文件。
  4. 运行elf

qemu-system-arm.exe -machine mps2-an385 -monitor null -semihosting --semihosting-config enable=on,target=native -kernel $(APP) -serial stdio -nographic
在这里插入图片描述

  1. 调试运行elf
    a. -S表示暂停在固件的起始指令。
    b. -s是-gdb tcp::1234的简写,表示启动tcp远程调试。

qemu-system-arm.exe -machine mps2-an385 -monitor null -semihosting --semihosting-config enable=on,target=native -kernel $(APP) -serial stdio -nographic -S -s
在这里插入图片描述

  1. gdb调试
    在这里插入图片描述

  2. 结果
    在这里插入图片描述

3.1.2. RISC-V

riscv-v使用Linux进行测试。

  1. 安装交叉编译工具链
    在https://www.sifive.com/software上下载工具链,并将路径添加进环境路径。

  2. 编译并运行
    在这里插入图片描述

  3. 调试
    方法同cortext-m7。

3.1.3. VSCode调试

gdb调试不太方便,利用VSCode可以更方便地查看变量,单步调试代码。添加lanch.json文件,将以下内容覆盖。按F5启动调试,代码即停止在main函数处。

 {
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch QEMU to debug HelloWorld.elf",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/HelloWorld.elf",
            "cwd": "${workspaceFolder}",
            "miDebuggerPath": "arm-none-eabi-gdb",
            "miDebuggerServerAddress": "localhost:1234",
            "stopAtEntry": true,
            "preLaunchTask": "Run QEMU"
        }
    ]
}

3.1.4. 代码

代码包括完整的固件,只需要安装交叉编译工具和qemu,即可以测试。

  1. make 编译。
  2. make qemu 仿真运行。
  3. make qemu-remote
  4. gdb -x gdbinit启用调试。
    代码路径:https://github.com/feihe027/qemu_mcu

3.2. 嵌入式Linux

3.2.1. ubuntu

3.2.1.1. 安装运行

下面是Cortex-A57 CPU来安装Linux。

  1. 下载Linux镜像,从官方网站下载ubuntu-20.04-live-server-arm64.iso。(服务器版本无UI)
  2. 下载EFI启动文件

wget http://releases.linaro.org/components/kernel/uefi-linaro/16.02/release/qemu64/QEMU_EFI.fd -O /data/kvm/QEMU_EFI.fd

  1. 创建启动盘镜像

qemu-img create ubuntu20.04-arm64.img 32G

  1. 创建nvme SSD镜像

qemu-img create -f qcow2 nvme.qcow2 10G

  1. 安装系统
    注意,上面4个文件统一放到新建的虚拟机目录,进入目录执行下列命令

qemu-system-aarch64 -machine virt
-cpu cortex-a57
-smp 2
-m 4G
-bios QEMU_EFI.fd
-device virtio-scsi-device
-device scsi-cd,drive=cdrom
-drive if=none,file=ubuntu-20.04-live-server-arm64.iso,id=cdrom,media=cdrom
-device virtio-blk-device,drive=vd0
-drive if=none,file=ubuntu20.04-arm64.img,id=vd0
-drive file=nvme.qcow2,if=none,id=nvme0 -device nvme,drive=nvme0,serial=foo
-net nic -net tap,ifname=tap0,script=no,downscript=no -nographic

几分钟后安装界面,默认往下执行即可,设置用户名密码等,最终进入安装流程,安装会比较慢。安装完成之后,直接关闭当前控制台窗口,不要选Restart,会重新进行安装。
6. 启动虚拟机
启动虚拟机和安装差不多,只是不用cdrom系统文件,直接从镜像启动即可。

qemu-system-aarch64 -machine virt
-cpu cortex-a57
-smp 2
-m 4G
-bios QEMU_EFI.fd
-device virtio-blk-device,drive=vd0
-drive if=none,file=ubuntu20.04-arm64.img,id=vd0
-drive file=nvme.qcow2,if=none,id=nvme0 -device nvme,drive=nvme0,serial=foo
-net nic -net tap,ifname=tap0,script=no,downscript=no -nographic

启动之后,等一两分钟,就会进入系统,输入用户名密码登录。
在这里插入图片描述

3.2.2. 调试内核

3.2.2.1. 编译内核
  1. 下载Kernel代码,测试使用6.8-rc5

git clone https://gitee.com/mirrors/linux_old1.git

  1. 安装工具链

sudo apt-getinstall gcc-aarch64-linux-gnu

  1. 配置内核选项

cd linux_old1
// arch/arm64/configs/defconfig 中将CONFIG_RANDOMIZE_BASE=y修改成CONFIG_RANDOMIZE_BASE=n
// 检查CONFIG_DEBUG_KERNEL=y
// 检查CONFIG_DEBUG_INFO_REDUCED=y
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig

  1. 编译内核
    make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j8
    根文件系统制作
    根文件系统制作
  2. 下载最新busybox
  3. 配置busybox
    make menuconfig
    Settings —>
    [] Build static binary (no shared libs) //静态编译
    [
    ] Build with debug information //可选,带调试信息,方便后续调试
  4. 编译
    make && make install
3.2.2.2. 制作根文件

qemu-img create rootfs.img 512m
mkfs.ext4 rootfs.img
mkdir rootfs
sudo mount rootfs.img rootfs
sudo cp -rf _install/* rootfs
cd rootfs
sudo mkdir proc sys dev etc etc/init.d
sudo vim etc/init.d/rcS
sudo chmod +x etc/init.d/rcS
cd …
sudo umount rootfs
//# etc/init.d/rcS文件内容如下
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug

3.2.2.3. 运行
  1. 将arch/arm64/boot/Image 和rootfs.img 文件拷贝到任意目录。
  2. 执行下面命令

qemu-system-aarch64 -machine virt,virtualization=true,gic-version=3 -nographic -m size=1024M -cpu cortex-a72 -smp 2 -kernel Image -drive format=raw,file=rootfs.img -append “root=/dev/vda rw”

  1. 系统开始启动
    在这里插入图片描述
3.2.2.4. 调试
  1. 远程启动

qemu-system-aarch64 -machine virt,virtualization=true,gic-version=3 -nographic -m size=1024M -cpu cortex-a72 -smp 2 -kernel Image -drive format=raw,file=rootfs.img -append “root=/dev/vda rw nokaslr” -S -s

  1. 调整GDB权限问题
    创建/root/.gdbinit文件,并写入以下信息

set auto-load safe-path /

  1. 启动GDB
    进入Kernel源代码目录,执行gdb-multiarch vmlinux。vmlinux是原始的内核elf文件,Image文件则是压缩之后的elf文件。
    在这里插入图片描述
  2. 连接远程调试,添加断点函数
    在这里插入图片描述
  3. VSCode调试
    gdb调试不太方便,用VSCode更方便。用VSCode打开Kernel源代码,在.vscode目录添加launch.josn文件,内容如下,然后找到init/main.c的的start_kernel函数下断点,然后按F5启动调试。
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch QEMU to debug HelloWorld.elf",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/vmlinux",
            "cwd": "${workspaceFolder}",
            "miDebuggerPath": "gdb-multiarch",
            "miDebuggerServerAddress": "localhost:1234",
            "stopAtConnect": true,
            "stopAtEntry": true,
        }
    ]
}

在这里插入图片描述

4. 扩展QEMU

4.1. 下载代码

开发代码基于qemu 8.2.1版本。

git clone https://gitee.com/mirrors/qemu.git

4.2. 编译

要扩展QEMU的功能,肯定需要用到调试,所以编译时需要打开debug选项,并且可以指定编译的工具来减少编译时间。详细编译配置,参见./configure -help。如下只编译riscv版本。

./configure --target-list=riscv32-softmmu --enable-debug --disable-werror
make -j8

4.3. 添加uart

qemu是默认一块完整的开发板,其模拟的硬件不仅有cpu,还有各种外设。相关代码放在hw目录,uart外设则放 在char目录中。

  1. 添加uart代码。
    cmsdk-apb-uart是mps2主板(支持Cortext-M7)配套的uart,我们将其移植到riscv中来。将cmsdk-apb-uart改为ys_uart。并将函数中的cmsdk-apb-uart也相应修改为ys_uart。
  2. 添加打印函数
    uart中用到的一些函数,是编译时python调用trace-event文件中的相关描述生成的。所以在trace-event中添加:

ys_uart.c

ys_uart_read(uint64_t offset, uint64_t data, unsigned size) “CMSDK APB UART read: offset 0x%” PRIx64 " data 0x%" PRIx64 " size %u"
ys_uart_write(uint64_t offset, uint64_t data, unsigned size) “CMSDK APB UART write: offset 0x%” PRIx64 " data 0x%" PRIx64 " size %u"
ys_uart_reset(void) “CMSDK APB UART: reset”
ys_uart_receive(uint8_t c) “CMSDK APB UART: got character 0x%x from backend”
ys_uart_tx_pending(void) “CMSDK APB UART: character send to backend pending”
ys_uart_tx(uint8_t c) “CMSDK APB UART: character 0x%x sent to backend”
ys_uart_set_params(int speed) “CMSDK APB UART: params set to %d 8N1”

  1. 编译配置
    qemu是采用kconfig配置和meson来编译的,所以需要配置char目录的Kconfig文件,添加:

system_ss.add(when: ‘CONFIG_YS_UART’, if_true: files(‘ys_uart.c’))
Kconfig文件添加
config YS_UART
bool

  1. 给hw/riscv/virt.c添加自定义的uart
#include "hw/char/ys_uart.h"  // 添加头文件

// 在函数virt_machine_inti中添加如下代码
DeviceState *dev = qdev_new(TYPE_YS_UART);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
qdev_prop_set_chr(dev, "chardev", serial_hd(0));
qdev_prop_set_uint32(dev, "pclk-frq", 25000000);
sysbus_realize_and_unref(sbd, &error_fatal);
sysbus_mmio_map(sbd, 0, 0x40004000);
// 上面的代码为新添加
serial_mm_init(system_memory, memmap[VIRT_UART0].base,
                   0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193,
                   serial_hd(1), DEVICE_LITTLE_ENDIAN);
  1. 修改machine名
    将hw/riscv/virt.c、virt.h中的
    MACHINE_TYPE_NAME(“virt”),
    // 修改为
    MACHINE_TYPE_NAME(“ys_virt”),
  2. 代码
    相关代码见:https://gitee.com/michael_duan/qemu_riscv.git

4.4. 测试

4.4.1. 固件


#define UART0_ADDRESS (0x40004000UL)
#define UART0_DATA (*(((volatile uint32_t *)(UART0_ADDRESS + 0UL))))
#define UART0_STATE (*(((volatile uint32_t *)(UART0_ADDRESS + 4UL))))
#define UART0_CTRL (*(((volatile uint32_t *)(UART0_ADDRESS + 8UL))))
#define UART0_BAUDDIV (*(((volatile uint32_t *)(UART0_ADDRESS + 16UL))))
#define TX_BUFFER_MASK (1UL)

static void InitUart(void)
{
    UART0_BAUDDIV = 16;
    UART0_CTRL = 1;
}
/*-----------------------------------------------------------*/

static int UartWrite(char *pcString, int iStringLength)
{
    int iNextChar;

    /* Output the formatted string to the UART. */
    for (iNextChar = 0; iNextChar < iStringLength; iNextChar++)
    {
        while ((UART0_STATE & TX_BUFFER_MASK) != 0)
        {
        }

        UART0_DATA = *pcString;
        pcString++;
    }

    return iStringLength;
}

int main(void)
{
    InitUart();
    UartWrite("Hello World!\n", 13);

    while (1)
    {
        /* code */
    }
}

4.4.2. 调试

调试qemu,利用VSCode更,在.vscode目录中添加launch.json文件,添加如下内容:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug",
            "type": "cppdbg",
            "request": "launch",
            "args": ["-machine", "ys_virt", "-serial", "stdio", "-nodefaults",  "-bios", "none", "-smp", "1",  "-nographic",  "-kernel", "e:\\HelloWorld_riscv.elf"],
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "stopAtEntry": false,
            "windows": {
                "MIMode": "gdb",
                "miDebuggerPath": "C:\\msys64\\mingw64\\bin\\gdb.exe",
                "program": "${workspaceFolder}\\build\\qemu-system-riscv32.exe",
            },
        }
    ]
}

在\system\main.c的int main(int argc, char **argv)处添加断点,按F5调试,显示如下:
在这里插入图片描述

4.4.3. 验证

./build/qemu-system-riscv32.exe -machine ys_virt -serial stdio -nodefaults -bios none -kernel /e/HelloWorld_riscv.elf -nographic

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【竞技宝jjb.lol】LOL:wayward奎桑提主宰团战 WE2-1力克IG

北京时间2024年2月24日&#xff0c;英雄联盟LPL2024春季常规赛继续进行&#xff0c;昨日共进行三场比赛&#xff0c;第二场比赛由IG对阵WE。本场比赛双方前两局战至1-1平&#xff0c;决胜局WE中期抓住IG失误后拿下大龙奠定胜局&#xff0c;最终WE2-1力克IG。以下是本场比赛的详…

二次元风格个人主页HTML源码

源码介绍 直接上传服务器压缩包解压就完事了&#xff0c;修改index.html内代码即可&#xff0c;注释写的很全&#xff0c;替换图片在文件夹img&#xff0c;只有前端&#xff0c;没有后台&#xff0c;大佬如果需要&#xff0c;可以自行添加后台。本源码非常适合个人工作室主页。…

利用psutil库检查脚本是否在运行

摘要 如果要判断某一脚本是否在运行&#xff0c;可以通过psutil库获取所有进程的cmdline&#xff0c;并判断指定的文件名是否在cmdline中。 目录 1.psutil库简介 2.检查代码及说明 2.1检查思路 2.2异常捕获 2.3执行方法 1.psutil库简介 psutil 是一个跨平台&#xff08;…

Optimization for Deep Learning

Notations: : model parameters at time step or : gradient at used to compute : momentum accumulated from time step to time step , which is used to cpmpute Optimization What is Optimization about? 找到一组参数&#xff0c;使得 最小&#xff0c;或者说是…

内容安全补充

第十一天 密码学 近现代加密算法 古典加密技术 --- 算法保密原则 近现代加密技术 --- 算法公开&#xff0c;密钥保密 对称加密算法&#xff0c;非对称加密算法 对称加密 --- 加密和解密的过程中使用的是同一把密钥。 所以&#xff0c;对称加密所使用的算法一定是一种双向…

概率基础——指数分布

概率基础——指数分布 介绍 指数分布是一种连续概率分布&#xff0c;描述了独立随机事件之间的时间间隔。它常被用来模拟随机事件的等待时间&#xff0c;例如到达下一位顾客的等待时间、设备故障的间隔时间等。指数分布具有无记忆性的特点&#xff0c;即在给定时间内没有发生…

*MYSQL--索引--内部原理

MYSQL的索引根据功能,主要有三大类型: 1.HASH索引 2.二叉树 3.BTREE索引 一:HASH索引 1.内部原理: 在设置了某列为索引列之后,并且开始或者将要在相应索引列创建数据的时候,系统通过某种算法 F(X) 自动计算出来一个十六进制的哈希值,这个哈希值能够对应相应的字段值 所以…

单片机51 输入和输出

一、IO口基本概念介绍 单片机的IO口&#xff08;Input/Output口&#xff09;是连接单片机与外部电路或设备的接口。单片机的IO口可以分为输入口和输出口两种&#xff0c;用于控制和监测外部设备的状态。 1. 输入口&#xff1a;单片机的输入口用于接收外部电路或设备的信号。输…

C++的string容器->基本概念、构造函数、赋值操作、字符串拼接、查找和替换、字符串比较、字符存取、插入和删除、子串

#include<iostream> using namespace std; #include <string> //string的构造函数 /* -string(); //创建一个空的字符串 例如: string str; -string(const char* s); //使用字符串s初始化 -string(const string& str); //使…

Linux安装jdktomcatMySQl一战完成

一、jdk安装具体步骤 1、查询是否有jdk java -version 2、进入opt目录 cd /opt/ 连接服务器工具 进入opt目录&#xff0c;把压缩文件上传 查询是否查询成功 进入解压到的目录 cd /usr/local/创建新文件夹 mkdir java 再回到opt目录进行解压 cd /opt 解压到刚刚创建的文…

springboot邮箱注册

1.准备工作 操作之前准备两个邮箱 我准备了网易邮箱和QQ邮箱&#xff0c;网易邮箱用来发送验证码&#xff0c;QQ邮箱用来做注册&#xff08;希望大家和我一样&#xff0c;不然可能会出错 &#xff09; 发送验证码的邮箱需要开启一些设置&#xff0c;否则不…

CSS 字体和文本详解

CSS 字体和文本详解 字体设置 如果字体名有空格&#xff0c;使用引号包裹。建议使用常见字体&#xff0c; 否则兼容性不好。字体名称可以用英文&#xff0c;也可以用中文&#xff0c; 推荐使用英文。 示例代码: 运行结果: 字体大小 不同的浏览器默认字号不一样&#xff0c;…

多线程相关(4)

线程安全-下 使用层面锁优化减少锁的时间&#xff1a;减少锁的粒度&#xff1a;锁粗化&#xff1a;使用读写锁&#xff1a;使用CAS&#xff1a; 系统层面锁优化自适应自旋锁锁消除锁升级偏向锁轻量级锁重量级锁 ThreadLocal原理ThreadLocal简介原理ThreadLocal内存泄漏 HashMap…

15-36V降压充电光伏MPPT充电方案

1.MPPT原理--简介 MPPT&#xff0c;全称为Maximum Power Point Tracking&#xff0c;即最大功点跟踪&#xff0c;它是一种通过调节电气模块的工作状态&#xff0c;使光伏板能够输出更多电能的电气系统能够将太阳能电池板发出的直流电有效地贮存在蓄电池中&#xff0c;可有效地…

【Langchain多Agent实践】一个有推销功能的旅游聊天机器人

【LangchainStreamlit】旅游聊天机器人_langchain streamlit-CSDN博客 视频讲解地址&#xff1a;【Langchain Agent】带推销功能的旅游聊天机器人_哔哩哔哩_bilibili 体验地址&#xff1a; http://101.33.225.241:8503/ github地址&#xff1a;GitHub - jerry1900/langcha…

从软硬件以及常见框架思考高并发设计

目录 文章简介 扩展方式 横向扩展 纵向扩展 站在软件的层面上看 站在硬件的层面上看 站在经典的单机服务框架上看 性能提升的思考方向 可用性提升的思考方向 扩展性提升的思考方向 文章简介 先从整体&#xff0c;体系认识&#xff0c;理解高并发的策略&#xff0c;方…

xff注入 [CISCN2019 华东南赛区]Web111

打开题目 看见smarty 想到模板注入 又看见ip 想到xff注入 一般情况下输入{$smarty.version}就可以看到返回的smarty的版本号。该题目的Smarty版本是3.1.30 在Smarty3的官方手册里有以下描述: Smarty已经废弃{php}标签&#xff0c;强烈建议不要使用。在Smarty 3.1&#xff…

vue实现递归组件

父组件&#xff1a; <Tree :data"data"></Tree> import Tree from "/components/Tree.vue"; const data reactive([{name: "1",checked: true,children: [{name: "1-1",checked: false,},],},&#xff09; 子组件&#…

电脑闹钟软件哪个好用?

电脑闹钟软件哪个好用&#xff1f;一款带有闹钟定时提醒的备忘录软件是比较实用的&#xff0c;很多上班族每天都要处理堆积如山的工作&#xff0c;总是会忙于一件事的时候忘记另外一件事&#xff0c;导致效率极低。如当一项重要会议需要提前准备资料时&#xff0c;我们却忙于其…

【大厂AI课学习笔记NO.51】2.3深度学习开发任务实例(4)计算机视觉实际应用的特点

今天考试通过腾讯云人工智能从业者TCA级别的认证了&#xff01; 还是很开心的&#xff0c;也看不到什么更好的方向&#xff0c;把一切能利用的时间用来学习&#xff0c;总是对的。 我把自己考试通过的学习笔记&#xff0c;都分享到这里了&#xff0c;另外还有一个比较全的思维…