VSCode编辑+GCC for ARM交叉编译工具链+CMake构建+OpenOCD调试(基于STM32的标准库/HAL库)

embedded/2024/12/21 15:45:37/

一、CMake安装

  • 进入CMake官网的下载地址Get the Software,根据系统安装对应的Binary distributions。
    在这里插入图片描述
  • 或者在CMake——国内镜像获取二进制镜像安装包。 在这里插入图片描述
  • 或者访问GitHub的xPack项目xPack CMake v3.28.6-1,下载即可。

记得添加用户/系统的环境变量,打开cmd窗口,输入cmake -version,查看CMake环境变量是否添加成功,如下图所示。
在这里插入图片描述

二、VSCode各个配置脚本文件

本文以【STM32F103ZET6】单片机作为示例来进行演示,以下配置文件对于标准库/HAL库的工程是通用的,修改CMakeLists.txt里面的源文件和头文件引用部分即可。
更多细节请参考【VSCode编辑+GCC for ARM交叉编译工具链+Makefile构建+OpenOCD调试(基于STM32的标准库)】
下面列出几个主要的配置文件:

  • settings.json

  • c_cpp_properties.json

  • tasks.json

  • launch.json

  • CMakeLists.txt

  • MCU链接脚本.ld、MCU汇编启动文件.s、MCU寄存器文件.svd请参考【VSCode编辑+GCC for ARM交叉编译工具链+Makefile构建+OpenOCD调试(基于STM32的标准库)】文章获取。

settings.json:

{// 字符集编码选择"files.encoding": "utf8",// 自动保存任意文件"files.autoSave": "afterDelay",// 开启 material icons"workbench.iconTheme": "office-material-icon-theme",// theme主题设置"workbench.colorTheme": "Default Dark Modern",//粘贴时格式化代码"editor.formatOnPaste": true,//保存时格式化代码"editor.formatOnSave": true,//设置字体的大小,最小值能设置为6"editor.fontSize": 15,//设置字体的粗细"editor.fontWeight": "500",//设置字体的样式// "terminal.integrated.fontFamily":"Courier New",//使用Ctrl+滚轮缩放编辑区的字体大小"editor.mouseWheelZoom": true,//使用Ctrl+滚轮缩放终端Terminal的字体大小"terminal.integrated.mouseWheelZoom": true,//设置为false,这样打开新的文件时,不会自动关闭旧的文件"workbench.editor.enablePreview": false,"security.workspace.trust.enabled": false,"VsCodeTaskButtons.showCounter": true,"VsCodeTaskButtons.tasks": [{"label": "$(tools) Build", // 显示标签"task": "CMake build", // 对应tasks.json里的任务label"tooltip": "🛠️ build" // 工具提示框},{"label": "$(notebook-delete-cell) Clean","task": "CMake clean","tooltip": "🧹 clean"},{"label": "$(notebook-delete-cell) $(tools) Re-bulid", //"$(notebook-delete-cell) & $(tools)","task": "CMake cleanRebuild","tooltip": "🛠️ rebuild" // "🧹 & 🛠️ rebuild"},{"label": "$(zap) Download",// "task": "CMake download","tasks": [{"label": "⚓ CMSIS-DAP-Link", //icon copied from https://emojipedia.org/"task": "flash with CMSIS-DAP-Link"},{"label": "⤵️ ST-Link", //icon copied from https://emojipedia.org/"task": "flash with ST-Link"},{"label": "🚀 J-Link", //icon copied from https://emojipedia.org/"task": "flash with J-Link"}],"tooltip": "⚡ download"}],
}

c_cpp_properties.json:

{"configurations": [{"name": "Win32-arm-gcc-dev","includePath": [    // 设置编辑器中的头文件查找目录"${workspaceFolder}/**"],"defines": ["_DEBUG","UNICODE","_UNICODE","__MICROLIB","__CC_ARM"      // 解决编辑器中提示无法识别uint32_t, uint16_t, uint8_t的问题],"compilerPath": "E:/embedded_dev_tools/xpack-arm-none-eabi-gcc-13.3.1-1.1/bin/arm-none-eabi-gcc.exe",//解决编辑器中提示无法识别例如__attribute__((weak))等gcc编译器功能选项"cStandard": "gnu17",   // 设置使用的C标准"cppStandard": "gnu++17", // 设置使用的C++标准"intelliSenseMode": "gcc-arm", // 设置编译器类型,解决编辑器中提示无法识别例如__attribute__((weak))等gcc编译器功能选项"configurationProvider": "ms-vscode.cmake-tools"}],"version": 4
}

tasks.json:

{//快捷键ctrl+shift+B调出各个task命令"tasks": [{"type": "cmake","label": "CMake build","command": "build","targets": ["${workspaceRootFolderName}.elf"],"group": "build","problemMatcher": ["$gcc"]},{"type": "cmake","label": "CMake cleanRebuild","command": "cleanRebuild","targets": ["${workspaceRootFolderName}.elf"],"group": "build","problemMatcher": ["$gcc"]},{"type": "cmake","label": "CMake clean","command": "clean","problemMatcher": ["$gcc"]},{"type": "shell","label": "flash with CMSIS-DAP-Link","command": "openocd","args": ["-f","interface/cmsis-dap.cfg","-f","target/stm32f1x.cfg","-c","program build/${workspaceRootFolderName}.elf verify reset exit"],"problemMatcher": ["$gcc"],"group": "build"},{"type": "shell","label": "flash with ST-Link","command": "openocd","args": ["-f","interface/stlink.cfg","-f","target/stm32f1x.cfg","-c","program build/${workspaceRootFolderName}.elf verify reset exit"],"problemMatcher": ["$gcc"],"group": "build"},{"type": "shell","label": "flash with J-Link","command": "openocd","args": ["-f","interface/jlink-swd.cfg","-f","target/stm32f1x.cfg","-c","program build/${workspaceRootFolderName}.elf verify reset exit"],"problemMatcher": ["$gcc"],"group": "build"}],"version": "2.0.0"
}

launch.json:

{// 使用 IntelliSense 了解相关属性。// 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "Debug with CMSIS-DAP-Link","cwd": "${workspaceRoot}","executable": "./build/${workspaceRootFolderName}.elf","request": "launch","type": "cortex-debug","servertype": "openocd","device": "STM32F103VET6",// "openOCDLaunchCommands": [//     "adapter speed 10000"// ],"configFiles": ["interface/cmsis-dap.cfg", // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/interface"target/stm32f1x.cfg" // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/target],"svdFile": "./STM32F103.svd", //选择寄存器文件"liveWatch": {"enabled": true,"samplesPerSecond": 4},"searchDir": [],"runToEntryPoint": "main","showDevDebugOutput": "none","preLaunchTask": "flash with CMSIS-DAP-Link"},{"name": "Debug with ST-Link","cwd": "${workspaceRoot}","executable": "./build/${workspaceRootFolderName}.elf","request": "launch","type": "cortex-debug","servertype": "openocd","device": "STM32F103VET6",// "openOCDLaunchCommands": [//     "adapter speed 10000"// ],"configFiles": ["interface/stlink.cfg", // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/interface"target/stm32f1x.cfg" // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/target],"svdFile": "./STM32F103.svd", //选择寄存器文件"liveWatch": {"enabled": true,"samplesPerSecond": 4},"searchDir": [],"runToEntryPoint": "main","showDevDebugOutput": "none","preLaunchTask": "flash with ST-Link"},{"name": "Debug with J-Link","cwd": "${workspaceRoot}","executable": "./build/${workspaceRootFolderName}.elf","request": "launch","type": "cortex-debug","servertype": "openocd","device": "STM32F103VET6",// "openOCDLaunchCommands": [//     "adapter speed 10000"// ],"configFiles": ["interface/jlink-swd.cfg", // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/interface"target/stm32f1x.cfg" // D:/Software/arm_riscv_develop_tools/openocd/openocd/scripts/target],"svdFile": "./STM32F103.svd", //选择寄存器文件"liveWatch": {"enabled": true,"samplesPerSecond": 4},"searchDir": [],"runToEntryPoint": "main","showDevDebugOutput": "none","preLaunchTask": "flash with J-Link"}]
}

三、CMakeLists.txt——构建文件

CMakeLists.txt:

#THIS FILE IS AUTO GENERATED FROM THE TEMPLATE! DO NOT CHANGE!
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
# cmake最低版本需求
cmake_minimum_required(VERSION 3.20)# 设置编译器:specify cross compilers and tools
# 当编译工具链路径被加到环境变量中,可以直接写编译工具的名称;若未加入环境变量,此处应写对应交叉编译工具链的绝对路径。
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
# 链接的类型设置为STATIC, 以便嵌入式ARM-GNU通过CMake的"编译器检查"
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)# project : 定义工程名称,并可以指定工程可支持的语言,语法格式为 project(项目域名 语言)
# .HEX  .bin  .elf  .map的文件名设置
project(Led_Toggle  C CXX ASM)
# C/C++语言标准版本配置
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)#Uncomment for hardware floating point
#add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
#add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
#add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)#Uncomment for software floating point
#add_compile_options(-mfloat-abi=soft)#编译选项定义
#   对于 cortex-m3
#   +---------------------------------------------------+
#   | -mthumb -mcpu=cortex-m3 或 -mthumb -march=armv7-m |
#   +---------------------------------------------------+ #   对于 cortex-m4
#   +---------------------------------------------------+
#   | -mthumb -mcpu=cortex-m4 或 -mthumb -march=armv7-m|
#   +---------------------------------------------------+ #   对于 cortex-m7
#   +---------------------------------------------------+
#   | -mthumb -mcpu=cortex-m7 或 -mthumb -march=armv7-m |
#   +---------------------------------------------------+ # -mcpu=cortex-m3 告诉编译器为 ARM Cortex-M3 处理器生成代码
# -mthumb 启用 Thumb 指令集,Thumb 指令集是一种 16 位指令集
# -march=armv7-m 指定目标架构,ARMv7-M 是 Cortex-M3 处理器使用的架构
set(MCU_FLAGS -mcpu=cortex-m3 -mthumb -mthumb-interwork)    #   编译选项定义修改处#-fdata-sections用于将每个符号创建为一个sections,其中每个sections名与data名保持一致。
#-ffunction-sections用于将每个函数创建为一个sections,其中每个sections名与function名保持一致。
#用于代码的分割和裁剪,会将每一个函数都拆分成.text(Code+RO-data)段、.data(RW-data)段、.bss(ZI-data)段,这部分和对象文件的链接有关。如果没有这两个参数,编译器就会按文件分段而不是按照函数分段。
#加上这两个参数,配合链接器可以#去除代码中无用的部分,减少最终可执行文件的大小。
#-fno-common用于未初始化的全局变量当成强符号,重复定义就会报错。
#开启-fmessage-length=0会让编译器展示所有的消息而不会限制错误和警告输出的长度
set(OPTIMIZE_COMPILE_FLAGS -ffunction-sections -fdata-sections -fno-common -fmessage-length=0)
# 针对所有编译器,开启编译警告 (包括C、C++编译器),-Wall可开启所有警告;-Werror将所有警告视为error
# add_compile_options("-Wall -Werror")
add_compile_options(${MCU_FLAGS})
add_compile_options(${OPTIMIZE_COMPILE_FLAGS})# /*
# 编译等级选项:优化等级
# -O0:无任何优化,关闭所有优化选项
# -O、-O1:1级优化,
# -O2: 2级优化,
# -Os: 2.5级优化,-Os启用所有通常不会增加代码大小的-O2优化。 它还执行旨在减少代码大小的进一步优化。
# -O3: 最高级优化。
# -Og:优化调试体验。 -Og启用不会干扰调试的优化。 它是标准编辑 - 编译 - 调试周期可以选择的优化级别,提供合理的优化级别,同时保持快速编译和良好的调试体验。
# -Ofast:无视严格的标准合规性。 -Ofast启用所有-O3优化。 它还打开并非对所有符合标准的程序有效的优化。
# */#设置代码调试等级
set(CMAKE_BUILD_TYPE "Debug")
#   +---------------+--------------+--------------+----------+
#   |               | optimization | assert works | stripped |
#   +---------------+--------------+--------------+----------|
#   |     Debug     |     no       |     yes      |    no    |
#   |    Release    |    full      |      no      |   yes    |
#   | RelWithDebInfo|    good      |      no      |    no    |
#   |   MinSizeRel  |    size      |      no      |   yes    |
#   +---------------+--------------+--------------+----------+
# Release 进行优化,提高速度 -排除调试信息
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")message(VERBOSE "Maximum optimization for speed")add_compile_options(-Ofast)
# RelWithDebInfo 进行优化,提高速度 -包含调试信息
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")message(VERBOSE "Maximum optimization for speed, debug info included")add_compile_options(-Ofast -g)
# MinSizeRel 优化二进制大小 -排除调试信息
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")message(VERBOSE "Maximum optimization for size")add_compile_options(-Os)
# Debug 禁用优化 -包含调试信息
else ()message(VERBOSE "Minimal optimization, debug info included")add_compile_options(-O0 -g)
endif ()#添加C文件编译宏定义
add_definitions(-DUSE_HAL_DRIVER-DSTM32F103xE -DUSE_STDPERIPH_DRIVER -DSTM32F10X_HD)
# add_definitions(-DUSE_STDPERIPH_DRIVER -DSTM32F10X_HD)#添加头文件路径,即.h文件
include_directories(./STM32F10x_FWLib/inc./SYSTEM/delay ./SYSTEM/sys ./SYSTEM/usart ./HARDWARE/inc ./USER/inc ./CORE/inc./CMSIS/inc)#   这三个变量指代的内容是一致的,指的是工程编译产生的目录
#   +------------------+--------------------+--------------------------+
#   | CMAKE_BINARY_DIR | PROJECT_BINARY_DIR | <projectname>_BINARY_DIR |
#   +------------------+--------------------+--------------------------+#   这三个变量指代的内容是一致的,指的就是工程顶级目录
#   +------------------+--------------------+--------------------------+
#   | CMAKE_SOURCE_DIR | PROJECT_SOURCE_DIR | <projectname>_SOURCE_DIR |
#   +------------------+--------------------+--------------------------+  #添加汇编启动文件路径,startup文件是STM32CubeMX生成的(需要gcc版本,不要使用MDK版本)
ENABLE_LANGUAGE(ASM) #为了让cmake识别启动文件
set(SRC_STARTUP "${CMAKE_SOURCE_DIR}/startup_s/startup_stm32f103xe.s")#添加源文件路径,即.c文件
#file语法,前一个参数是固定的GLOB_RECURSE, 后面一个参数自行定义
file(GLOB_RECURSE SOURCES ./STM32F10x_FWLib/src/*.c ./USER/src/*.c ./CMSIS/src/*.c./CORE/src/*.c ./SYSTEM/delay/*.c ./SYSTEM/sys/*.c ./SYSTEM/usart/*.c ./HARDWARE/src/*.c)#-specs=nosys.specs -specs=nano.specs选择链接精简C库newlib-nano,而非标准C库glibc/glibc++
#-u _printf_float显式启用浮点数打印  -u _scanf_float显式启用浮点数输入
set(OPTIMIZE_LD_FLAGS -Wl,--no-warn-rwx-segments -flto -specs=nano.specs -specs=nosys.specs -u _printf_float) # -u _scanf_float#添加.ld链接脚本路径
set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/link_script/STM32F103VETx_FLASH.ld")#-cref则生成交叉引用表方便查找未定义的符号引用(比如编译时出现的undefined reference)
#--print-memory-usage选项提供链接器文件中定义的每个内存区域使用的内存的详细信息
#输出.map文件
set(MAP_FLAGS -Wl,--cref,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)#链接选项配置
add_link_options(${MCU_FLAGS})
# add_link_options(-Wl,--no-warn-rwx-segments,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
# add_link_options(-specs=nano.specs -specs=nosys.specs -u _printf_float)   # -u _scanf_float
add_link_options(${OPTIMIZE_LD_FLAGS})
add_link_options(-T ${LINKER_SCRIPT})  
add_link_options(${MAP_FLAGS})#根据源文件、汇编启动文件、链接脚本 生成 .elf可执行文件
add_executable(${PROJECT_NAME}.elf ${SRC_STARTUP} ${SOURCES} ${LINKER_SCRIPT})set(ELF_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf)
set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)
set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin)add_custom_command(TARGET "${PROJECT_NAME}.elf" POST_BUILDCOMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}COMMENT "Building ${HEX_FILE}
Building ${BIN_FILE}")

CMakeLists.txt文件及注释的参考链接如下:
1)使用VScode开发STM32:基于CMake(包含标准库和HAL库工程)
2)VSCode 和 CMake 搭建嵌入式开发环境
3) 在Windows上使用VS Code搭建开发环境-基于STM32F103C8T6
4)cmake:设置编译选项
5)CMake进阶(一)设置编译选项
6)跨平台编译工具-CMake的语法特性与常用变量
7)【gcc】gcc优化等级 -O1 -O2 -O3 -Os -Ofast -Og|gcc关闭优化
8)arm-none-eabi-gcc编译、链接选项详解
9)gcc for arm 工具链使用(一)

📚NOTE:
①默认情况下,CMake使用本地编译器,如gcc,而嵌入式开发使用的是交叉编译器,如arm-none-eabi-gcc,CMake无法知道该使用哪个交叉编译器,因此需要明确地告知CMake。在VSCode中,CMake选择配置本地的arm-gcc或gcc工具链的方法步骤如下图所示,
在这里插入图片描述
同时修改c_cpp_properties.json"compilerPath"处为arm-none-eabi-gcc.exe的绝对路径,如下图所示,
在这里插入图片描述

②如果读者将上述的CMakeLists.txt文件移植到自己的标准库 / HAL库工程后,需要重新生成CMake和当前项目相关的配置,否则会报错。参考方法的截图如下,
在这里插入图片描述
③显式启用浮点数打印和输入功能的问题(未解决)

arm-none-eabi-gcc工具链发布时自带有2个基于newlib的预构建C库:一个是标准的newlib,另一个是newlib-nano(优化了代码大小)
要使用newlib-nano,用户应该提供额外的gcc编译和链接时选项:-specs=nano.specs。
在编译时,如果-specs=nano.specs被传递给编译器,那么一个专门为newlib-nano配置的“newlib.h”头文件会被使用。
nano.specs还能处理另外两个gcc库:libstdc++_nano.a和libsupc++_nano.a,它们同样针对代码大小进行了优化。
newlib-nano相比newlib,不仅仅是库的名字上的区别。浮点数的格式化input/output被实现为弱符号(隐式)。如果要使用%f,则必须通过显式指定"-u"命令选项来引入该符号。
参考链接:
1)Newlib 与 Newlib-Nano区别
2) [开发工具]为什么gcc编译出来的程序大小和Keil差别这么大
3)Shrink Your MCU code size with GCC ARM Embedded 4.7

#显式指定"-u"命令选项-u _scanf_float-u _printf_float

CMakeLists.txt的可选链接选项配置中,加入-u _printf_float,_scanf_float,虽然这样不会报错,但是load程序进MCU后,无法打印浮点数。
如下图所示,
在这里插入图片描述
如果仿照使用Makefile中一样的-u _printf_float -u _scanf_float显式启用,即如下图所示,则会发生报错:无法找到_scanf_float。
在这里插入图片描述
可能是笔者对CMake语法不熟悉,不太能理解在CMakeLists.txt中为何需写成-u _printf_float,_scanf_float才不报错(但是无法打印浮点数)。
所以最终笔者改成了只显式启用-u _printf_float 浮点数打印,没有加上显式启用-u _scanf_float浮点数输入。
如果各位读者对此有深入研究的见解,欢迎发表评论,指点笔者一二。


http://www.ppmy.cn/embedded/147563.html

相关文章

MySQL系列之数据类型(Numeric)

导览 前言一、数值类型综述二、数值类型详解1. NUMERIC1.1 UNSIGNED或SIGNED1.2 数据类型划分 2. Integer类型取值和存储要求3. Fixed-Point类型取值和存储要求4. Floating-Point类型取值和存储要求 结语精彩回放 前言 MySQL系列最近三篇均关注了和我们日常工作或学习密切相关…

存储过程(详细-附样例)

所有样例都是在mysql5.7版本下执行的&#xff0c;如果用其他数据库&#xff0c;请根据对应的数据库存储过程定义更改语句。 主体目录 一、存储过程相关命令 二、存储过程 2、参数 3、变量 4、if 流程控制 5、case 条件控制 6、while 循环语句 7、repeat 循环语句 8、…

云计算HCIP-OpenStack03

书接上回&#xff1a; 云计算HCIP-OpenStack02-CSDN博客 10.KeyStone keystone-Openstack&#xff0c;IAM服务&#xff08;统一身份认证&#xff09;-云服务 建议先去了解Hadoop&#xff08;大数据生态系统&#xff09;中的kerberos&#xff08;LDAPkerberos的鉴权机制&#xf…

vue-element-admin npm install 安装失败,tui-editor更名导致

导语&#xff1a; 本失败原因是由于tui-editor&#xff08;富文本编辑器插件&#xff09;更名造成的&#xff0c;现在已经更名为toast-ui/editor&#xff1b; 在一个是一直以为是我的git问题 报错代码&#xff1a;code 128 ..........&#xff0c;困扰了我好长时间&#xff…

分布式链路追踪简介-01-dapper 论文思想介绍

开源项目 auto-log 自动日志输出 分布式链路追踪简介 随着业务系统的不断发展、微服务架构的演进&#xff0c;从原来的单体应用架构、垂直应用架构、分布式 SOA 架构到现在的微服务架构&#xff0c;系统逐步走向微服务化以适应用户高并发请求等需求。 在微服务架构中&#…

【C#】方法参数的修饰符ref 与 out

在 C# 中&#xff0c;ref 和 out 是方法参数的修饰符&#xff0c;用于将参数 按引用传递&#xff0c;而不是按值传递。这允许方法修改调用者传递的变量的值。尽管它们的行为类似&#xff0c;但有重要的区别和适用场景。 1. ref 的含义与使用 含义 引用传递&#xff1a; 参数通…

将HTML转换为PDF:使用Spire.Doc的详细指南(二)无水印版

目录 引言 一、准备工作 1. 下载Spire.Doc for Java破解版 2. 将JAR包安装到本地Maven (1) 打开命令提示符 (2) 输入安装命令 (3) 在pom.xml中导入依赖 二、实现HTML到PDF的转换 1. 创建Java类 2. 完整代码示例 3. 代码解析 4. 处理图像 5. 性能优化 6. 错误处理…

TCP三次握手,四次挥手

三次握手 第一次握手&#xff1a;客户端向服务器发送一个 SYN 包&#xff0c;其中 SYN 标志位被设置为 1&#xff0c;表示客户端请求建立连接&#xff0c;并随机生成一个初始序列号 seqx 。此时客户端进入 SYN_SENT 状态&#xff0c;等待服务器的确认1.第二次握手&#xff1a;服…