自动驾驶工具工作记录

C++

issues

issue 1

error LINK2001: 无法解析的外部符号public: static struct QMetaObject const DataHandlerBase::staticMetaObject

原因是自定义的链接库没有导出相关类或者函数

sregex_token_iterator的特性

string 转数字

关于时间的函数和结构体

time 函数

1
2
#include <time.h>
time_t time(time_t* calptr)

得到自 1970-1-1 00:00:00 以来经过的秒数,结果可以通过返回值,也可以通过参数得到

1
2
3
4
time_t now;
time(&now);
// 等同于 now = time(NULL)
printf("now time is %d\n", now);

localtime

1
2
3
4
5
6
7
8
9
10
11
12
13
struct tm {
int tm_sec; /* 秒 – 取值区间为 [0,59] */
int tm_min; /* 分 - 取值区间为 [0,59] */
int tm_hour; /* 时 - 取值区间为 [0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为 [1,31] */
int tm_mon; /* 月份(从一月开始,0 代表一月) - 取值区间为 [0,11] */
int tm_year; /* 年份,其值等于实际年份减去 1900 */
int tm_wday; /* 星期 – 取值区间为 [0,6],其中 0 代表星期天,1 代表星期一 */
int tm_yday; /* 从每年 1 月 1 日开始的天数– 取值区间 [0,365],其中 0 代表 1 月 1 日 */
int tm_isdst; /* 夏令时标识符,夏令时 tm_isdst 为正;不实行夏令时 tm_isdst 为 0 */
};

struct tm *localtime(const time_t* calptr);

用来获取系统时间,精度为秒;将时间(秒)数值变换成本地时间,考虑到本地时区和夏令时标志

1
2
3
4
5
6
7
8
9
10
11
12
13
time_t now;
struct tm *tm_now;
time(&now);
tm_now = localtime(&now);
// 把秒变换成年月日
printf("now datetime: %d-%d-%d %d:%d:%d\n",
tm_now->tm_year+1900,
tm_now->tm_mon+1,
tm_now->tm_mday,
tm_now->tm_hour,
tm_now->tm_min,
tm_now->tm_sec
);

localtime_r

1
struct tm *localtime_r(const time_t *timep, struct tm *result);

用来获取系统时间,运行于 linux 平台下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <time.h>

int main()
{
time_t time_seconds = time(0);
struct tm now_time;
localtime_r(&time_seconds, &now_time);

printf("%d-%d-%d %d:%d:%d\n",
now_time.tm_year + 1900,
now_time.tm_mon + 1,
now_time.tm_mday,
now_time.tm_hour,
now_time.tm_min,
now_time.tm_sec
);
}

localtime_s

用来获取系统时间,运行于 windows 平台下,与 localtime_r 只有参数顺序不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 #include <iostream>
#include <time.h>

int main()
{
time_t time_seconds = time(0);
struct tm now_time;
localtime_s(&now_time,&time_seconds);
printf("%d-%d-%d %d:%d:%d\n",
now_time.tm_year + 1900,
now_time.tm_mon + 1,
now_time.tm_mday,
now_time.tm_hour,
now_time.tm_min,
now_time.tm_sec
);
}

localtimelocaltime_r 二者区别

  • localtime 对于多线程不安全,因为 localtime 在使用时,只需定义一个指针,申请空间的动作由函数自己完成,这样在多线程的情况下,如果有另一个线程调用了这个函数,那么指针指向的 struct tm结构体的数据就会改变
  • 在 localtime_slocaltime_r 调用时,定义的是 struct tm 的结构体,获取到的时间已经保存在 struct tm 中,并不会受其他线程的影响

gettimeofday

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <sys/time.h>

struct timezone {
int tz_minuteswest;/* 格林威治时间往西方的时差 */
int tz_dsttime;/*DST 时间的修正方式 */
}

struct timeval {
long int tv_sec; // 秒数
long int tv_usec; // 微秒数
}

int gettimeofday(struct timeeval* tv, struct timezone* tz);

获取秒、微秒、时区等信息;其参数 tv 是保存获取时间结果的结构体,参数 tz 用于保存时区结果,timezone参数若不使用则传入 NULL 即可

1
2
3
4
struct timeval tv_begin, tv_end;
gettimeofday(&tv_begin, NULL);
foo();
gettimeofday(&tv_end, NULL);

它获得的时间精确到微秒 1e-6s 量级,在一段代码前后分别使用 gettimeofday 可以计算代码执行时间

linux 下 sprintf_s 函数的替代

windows 平台下线程安全的格式化字符串函数sprint_s 并非标准 C 函数,因此 linux 下无法使用,但可以使用 snprintf 函数代替

1
2
3
4
5
6
7
8
9
10
11
12
/* 函数原型:*/
int snprintf(char *dest, size_t n, const char *fmt, ...);

/* 函数说明:最多从源串中拷贝 n-1 个字符到目标串中,然后再在后面加一个 0。所以如果目标串的大小为 n 的话,将不会溢出。
函数返回值:若成功则返回存入数组的字符数,若编码出错则返回负值。
推荐的用法:*/
void f(const char *p)
{
char buf[11] = { 0 };
snprintf(buf, sizeof(buf), "%10s", p); // 注意:这里第 2 个参数应当用 sizeof(str),而不要使用硬编码 11,也不应当使用 sizeof(str)-1 或 10
printf("%sn", buf);
}

incomplete type xxx used in nested name specifier

Error: incomplete type ‘QTime’ used in nested name specifier

声明 / 定义了 QTime 类型的变量,但是没有引入相应的头文件,即#include <QTime>

关于 filesystem 在 C++ 11、14、17 中的使用问题

  • 在 C++ 11 时,该类库定义在 std::tr2::sys 命名空间
  • C++ 14 中已经不存在 tr2 命名空间 filesystem 放在 std::experimental::filesystem 空间
    • 在(VS2019 以上)编译时可能会报错 C1189,提示该头文件已被取代,建议使用新的如果不想根据提示改用 C++ 17,那么我们可以坚持自己的想法,在项目配置中加预处理宏定义即可_SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
  • 不同的编译环境可以使用宏定义区分
    1
    2
    3
    4
    5
    #if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L)
    namespace fs = std::filesystem
    #else
    namespace fs = std::experimental::filesystem;
    #endif

‘filesystem’ in namespace ‘std’ does not name a type 出现这个报错可能是因为写错了
using fs = std::filesystemnamespace fs = std::filesystem

Windows 下 gb2312 编码的源文件,在 Linux 下编译报错

  • error: converting to execution character set: Invalid or incomplete multibyte or wide character
  • error: converting UCN to execution character set: Invalid or incomplete multibyte or wide character
  • failure to convert gbk to UTF-8
  • c++ 源文件有多种编码格式

gcc 编译选项

  • -finput-charset:输入字符集设置(需要和源文件编码一致),告诉编译器以什么样的编码形式读入源文件中的字符串
  • -fexec-charset:执行字符集设置(需要设置为当前运行环境支持的编码), 告诉编译器在内存中以什么样的编码形式保存字符串
  • -fwide-exec-charset:宽字符执行编码(在 windows 下应设置为 utf-16LE),告诉编译器在内存中以什么样的编码形式保存宽字符串

可能解决方法

尝试加上编码前缀

1
2
3
...
SysPrint::instance()->print(u8" 找到硬件解码器 hevc_qsv");
...

Visual Studio 无法打开编译器生成的文件:“xxx.obj”: Permission denied

删除其他配置平台编译后的文件,如 Debug 或 Relase 文件目录

不允许 dllimport 静态数据成员的定义

当要使用一个类的时候必须要有其定义,有两种方式:

  • 引用其头文件,即include "xxx.h"

  • 使用导出类,即使用 __declspec(dllimport) 定义的类为导出类

    1
    2
    3
    4
    class __declspec(dllimport) Test
    {

    }

    declspec(dllimport)是 msvc 特有的描述符,如果是跨平台的情况这样写就会有问题

    如果确实需要使用declspec(dllimport),msvc 规定:数据、静态数据成员和函数可以声明,但不能定义为dllimport;对于普通的函数、类可行,然而对模板却不行,需要考虑编译器能不能支持对模板的分离式编译

    一个 .cpp 及其包括的所有 .h 文件编译后叫做一个编译单元,即 .obj 文件,然后由链接器把所有的 .obj 链接生成一个可执行文件;模板是需要具体化的,编译器知道碰到使用这个模板代码的时候才会把模板编译成二进制代码

  • __declspec(dllexport):声明一个导出函数,这个函数从 .dll 文件导出。一般用于 .dll 中省掉在 DEF 文件中手动定义导出哪些函数的一个方法;如果过在 .dll 中全是 c++ 的类的话,无法在 DEF 文件中指定导出的函数,这能用 __declspec(dllexport) 导出类

  • __declspec(dllimport):声明一个导入函数,这个函数是从别的 .dll 中导入,一般用于使用某个 .dll 的可执行文件中;不适用 __declspec(dllimport) 也能正确编译代码,但是可以使编译器可以生成更好的代码;编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 .dll 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 .dll 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 .dll 中使用的变量

使用示例:

1
2
3
4
5
6
7
8
9
10
#if defined(LIBRARY)
#define SHARED_EXPORT Q_

DECL_EXPORT
#else
#define SHARED_EXPORT Q_DECL_IMPORT
#endif

#define Q_DECL_EXPORT __declspec(dllexport)
#define Q_DECL_IMPORT __declspec(dllimport)

Windows 编程

WMIC 指令

windows 批处理 打开 exe 后关闭黑窗口

1
start "" "xxx.exe"

如果下面这样调用,需要等待程序窗口关闭之后窗黑口才会关闭的
xxx.exe exit

findstr的使用

findstr 是一个在 Windows 系统的命令提示符或 PowerShell 中使用的命令行工具,主要用于在文本文件中搜索字符串。以下是一些关于findstr 的基本用法和选项:

基本字符串搜索

使用 findstr 可以在一个或多个文件中搜索包含特定字符串的行。例如,findstr "keyword" filename.txt将在 filename.txt 文件中搜索包含 “keyword” 的行

findstr支持使用正则表达式进行高级搜索。例如,findstr /r "^start" filename.txt将匹配以 “start” 开头的行

  • /B:在一行的开始配对模式
  • /E:在一行的结尾配对模式
  • /L:按字使用搜索字符串
  • /R:将搜索字符串作为正则表达式使用
  • /S:在当前目录和所有子目录中搜索匹配文件
  • /I:指定搜索不分大小写
  • /X:打印完全匹配的行
  • /V:只打印不包含匹配的行
  • /N:在匹配的每行前打印行数

搜索多个字符串

如果没有使用 /C 前缀,findstr 会使用空格分隔的搜索字符串。例如,findstr "hello there" x.y会在文件 x.y 中寻找 “hello”“there”

  • .:通配符,代表任何字符
  • *:重复,代表前一个字符或类出现零次或多次
  • ^:行的开始
  • $:行的结束
  • [class]:字符类,代表任何在字符集中的字符
  • [^class]:补字符类,代表任何不在字符集中的字符
  • [x-y]:范围,代表在指定范围内的任何字符

Linux

从 windows 拷贝文件到 WSL 最快速的方法

  • 在 WSL 用 sudo ls /mnt/* 列出系统所有的挂载盘,可以看到 windows 系统的所有盘都列出来了
  • 然后使用 cp 命令

安装 .deb 文件

1
sudo dpkg -i {packagen ame}

While dpkg -i indeed installs the package, it doesn’t do any automatic dependency resolution. Meanwhile there are two other alternative, using gdebi or the apt-get tool

  • 卸载 .deb
1
sudo dpkg -r {package name}
  • 删除目录
1
rm -rf {dir}

Git

递归 git push/pull

在 Git 中,递归 git push/pull 操作是指在父模块中递归地操作子模块的 push 和 pull 操作。当一个代码库包含多个子模块时,可以使用递归 git push/pull 操作来同时对所有子模块进行相关操作,从而避免了手动逐个操作子模块的繁琐

递归git push

1
git push --recurse-submodules=on-demand

递归git pull

1
git pull --recurse-submodules
  • 确保所有子模块都已经初始化和更新。如果有尚未初始化或更新的子模块,可以使用 git submodule initgit submodule update命令来初始化和更新子模块
  • 如果在父模块中进行了修改,并且同时也在某个子模块中进行了修改,那么在递归 git push/pull 操作时可能会出现冲突。如果出现冲突,需要手动解决冲突并再次进行递归 git push/pull 操作
  • 在进行递归 git push/pull 操作时,确保所有子模块的远程仓库地址正确设置,并且拥有 push/pull 权限

如何删除 Git 中的未跟踪文件 untracked files

要删除所有未跟踪的文件,可以运行以下命令

1
git clean -f # 该命令中的 -f 参数表示强制执行删除操作

如果想要删除未跟踪的文件和目录,可以使用 -d 参数

1
git clean -f -d

解决 Git 报 error unknown switch `e‘ 错误

在 VS Code 中,使用 git stash pop [<stash>] 语法报错

1
2
git stash pop stash@{0}
error unknown switch `e‘

花括号在 PowerShell 中被认为是代码块执行标识符,若想正常使用,可用反引号 ` 进行转义

1
git stash pop stash@`{0`}

git stash 某个特定的文件

可以使用 git stash 命令结合 git checkout 和 git add 来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 假设想要暂存文件 'specific_file.txt'

# 检查当前状态
git status

# 重置或暂存其他文件
# 例如,如果想暂存 'unwanted_file.txt',可以丢弃更改
git checkout -- unwanted_file.txt

# 或者如果想保留这些更改,可以将它们添加到暂存区
git add unwanted_file.txt

# 暂存特定文件
git stash push -m "stash specific_file.txt" specific_file.txt

# 现在 specific_file.txt 被暂存了,而其他更改仍然在工作目录中
# 也可以使用 git checkout-index 命令结合 git stash:

# 将特定文件复制到暂存区
git checkout-index --stdin < <(git diff --name-only specific_file.txt | git ls-files --stdin)

# 暂存所有更改,包括特定文件
git stash save -k "stash specific_file.txt"

# 现在,从暂存区中移除特定文件,这样它就不会出现在下一次提交中
git reset specific_file.txt

请注意,-k选项告诉 git stash 不要暂存那些已经被添加到暂存区的文件

git clone -depth 1 之后切换远程分支的方案

将 shallow clone 转换为 deep clone

1
2
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git fetch --unshallow

git config 是容易被忽视的,shallow clone 之后,remote.origin.fetch 的值是 +refs/heads/master:refs/remotes/origin/master,所以会发现怎么 fetch 都没有其他分支

SSH-keygen 用法

https 和 SSH 的区别

  • 前者可以随意克隆 github 上的项目,而不管是谁的;而后者则是你必须是你要克隆的项目的拥有者或管理员,且需要先添加 SSH key ,否则无法克隆
  • https url 在 push 的时候是需要验证用户名和密码的;而 SSH 在 push 的时候,是不需要输入用户名的,如果配置 SSH key 的时候设置了密码,则需要输入密码的,否则直接是不需要输入密码的

在 github 上添加 SSH key 的步骤

1
2
3
4
5
6
# -t 指定密钥类型,默认是 rsa ,可以省略
# -C 设置注释文字,比如邮箱
# -f 指定密钥文件存储文件名
ssh-keygen -t rsa -C "your_email@example.com"
clip < ~/.ssh/id_rsa.pub # 拷贝 id_rsa.pub 文件的内容
ssh -T git@github.com # 测试一下 SSH key

CMake

相关问题

issue 1

The target name
“xxx.cpp”
is reserved or not valid for certain CMake featres, such as generator expressions, and may result in undefined behavior.

原始问题

1
ADD_LIBRARY(${PROJECT} ${SRC_FILES} ${HEADER_FILES}) 

由于 CMakeLists.txt 文件中没有定义 ${PROJECT} 变量,ADD_LIBRARY少了一个参数导致报错

1
ADD_LIBRARY($XXX ${SRC_FILES} ${HEADER_FILES})

issue 2

  • Cannot specify link libraries for target “PRIVATE” which is not built by this project.
  • IMPORTED library can only be used with the INTERFACE keyword of target_link_libraries

原因同上,出现问题的语句:

1
TARGET_LINK_LIBRARIES(${PROJECT} Qt5::Widgets Qt5::Core)

issue 3

needed by xxx.so, not found (try using -rpath or -rpath-link)

没有将自己编译的动态库导入到 LD_LIBRARY_PATH

issue 4

如果已经在 CMakeLists.txt 中使用了CMAKE_AUTOMOC,则不需要手动调用qt5_wrap_cpp

issue 5

执行cmake --build path/build > build.log 构建 msvc 项目将日志重定向某个文本文档中乱码问题

CMake 增加编译参数和预处理指令

添加编译参数

  • 使用 add_compile_options 命令,这个命令将添加到所有的目标上 cmake add_compile_options(-Wall)
  • 使用 target_compile_options 命令,这个命令只会添加到指定的目标上,这种方法直接修改了 CMake 的全局变量,所以它会影响到所有的目标 cmake target_compile_options(target PRIVATE -Wall) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ...")

添加预处理指令

  • 使用 add_definitions 命令,这个命令将添加到所有的目标上 cmake add_definitions(-DDEBUG)
  • 使用 target_compile_definitions 命令,这个命令只会添加到指定的目标上 cmake target_compile_definitions(target PRIVATE DEBUG)
    • PRIVATE: 只有目标自己会使用这些编译参数
    • PUBLIC: 目标自己和其他依赖这个目标的目标都会使用这些编译参数
    • INTERFACE: 只有其他依赖这个目标的目标会使用这些编译参数

setlist 的字符串操作

set 拼接

1
2
#set(变量名 1 ${ 变量名 1} ${ 变量名 2} ...)
set(src1 ${src1} ${src2})

其实就是将从第二个参数开始往后所有的字符串进行拼接,最后将结果存储到第一个参数中,如果第一个参数中有数据就会对元数据进行覆盖

list

获取 list 的长度
1
list(LENGTH <list> <output_variable>)
  • LENGTH:子命令 LENGTH 用于读取列表长度
  • <list>:当前操作的列表
  • <output_variable>:新创建的变量,用户存储列表长度的结果
读取列表中指定索引的元素
1
2
3
list(GET <list> [<element_index>....] <output_variable>)

list(GET [....])
  • <list>:当前操作的列表
  • <element_index>:列表元素的索引
    • 从开始编号,索引表示 0 的元素为列表中的第一个元素
    • 索引也可以是负数,-1 表示列表的最后一个元素,-2 表示倒数第二个元素,以此类推
    • 当索引(不管正负)超过列表的长度,运行会报错
    • <output_variable>:新创建的变量,用户存储索引元素的返回结果,也是一个列表
将列表中的元素用连接符(字符串)连接起来组成一个字符串
1
list(JOIN <list> <glue> <output_variable>)
  • JOIN:子命令 JOIN 用于连接列表数据
  • <list>:当前操作的列表
  • <glue>:指定的链接符(字符串)
  • <output_variable>:新创建的变量,存储返回的字符串
查找 list 列表中是否存在指定的元素, 若未找到返回 -1
1
list(FIND <list> <value> <output_variable>)
  • FIND:表示进行查找操作
  • <list>:表示当前操作的列表
  • <value>:需要在列表中搜索的元素
  • <output_variable>:新创建的变量
    • 如果列表 <list> 中存在 <value> 那么返回 <value> 在列表中的索引
    • 如果未找到则返回 -1
列表排序
1
list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])
  • COMPARE:指定排序方法。有如下几种值可选:
    • STRING:按照字符顺序进行排序,为默认的排序方法
    • FILE_BASENAME:如果是一系列路径名,会使用 basename 进行排序
    • NATURAL:使用自然数顺序排序
  • CASE:指明大小写是否敏感,有如下两种值可选:
    • SENSITIVE:按照大小写敏感的方式进行排序,为默认值
    • INSENSITIVE:按照大小写不敏感方式进行排序
  • ORDER:指明排序的顺序,如有几种值可选
    • ASCENDING:按照升序排列,为默认值
    • DESCENDING:按照降序排列
其他操作
  • 将元素追加到列表尾部中 list(APPEND <list> [<element> ...])
  • 将元素插入到列表的 0 索引位置 list(PREPEND <list> [<element> ...])
  • 将列表中的最后元素移除 list(POP_BACK <list> [<output_variable> ...])
  • 将列表中的第一个元素移除 list(POP_FRONT <list> [<output_variable> ...])
  • 将指定元素从列表中移除 list(REMOVE_ITEM <list> [<value> ...])
  • 将指定索引的元素从列表中移除 list(REMOVE_AT <list> [<index> ...])
  • 移除列表中重复的元素 list(REMOVE_DUPLICATES <list>)
  • 列表翻转 list(REVERSE <list>)

虚拟机

VirtualBox Ubuntu22.04 Terminal 无法打开

CTRL + ALT + F3 进入命令行模式(需要返回桌面时 CTRL + ALT + F1)

1
2
3
4
5
6
cd /etc/default
sudo vi locale
# 把文件中的 en_US 改成 en_US.UTF-8
# 保存退出
sudo locate-gen --purge
reboot

VirtualBox 如何连接虚拟机与主机

NAT 网络:适用于基本互联网连接

NAT(网络地址转换)是 VirtualBox 默认的网络设置。它允许虚拟机通过主机的网络连接访问互联网,而无需额外的配置。虚拟机在 NAT 模式下无法被主机或局域网中的其他计算机访问,这意味着它具有很高的安全性

  • 配置步骤
    • 打开 VirtualBox,选择目标虚拟机,点击“设置”
    • 进入“网络”选项卡,确保“启用网络适配器”已选中
    • 网络连接方式选择“NAT”
    • 启动虚拟机,虚拟机将自动获取一个 IP 地址并通过主机的网络连接到互联网
  • 优点
    • 配置简单,无需进行复杂的网络设置
    • 对于只需要互联网连接的虚拟机非常方便
  • 缺点
    • 虚拟机无法被主机或局域网中的其他设备访问
    • 不适用于需要虚拟机与主机或其他虚拟机直接通信的场景

桥接网络:虚拟机与主机及局域网设备互通

桥接网络是 VirtualBox 提供的另一种网络模式,它允许虚拟机像主机一样直接连接到局域网。这意味着虚拟机将获得与主机在同一网段的 IP 地址,并且可以与局域网中的其他设备互相通信。这种模式特别适用于需要虚拟机与主机及其他局域网设备直接通信的场景

  • 配置步骤
    • 打开 VirtualBox,选择目标虚拟机,点击“设置”
    • 进入“网络”选项卡,确保“启用网络适配器”已选中
    • 网络连接方式选择“桥接适配器”
    • 从下拉菜单中选择主机的网络接口
    • 启动虚拟机,虚拟机将自动获取一个与主机同一网段的 IP 地址
  • 优点
    • 虚拟机与主机及局域网设备互通,无需额外的网络配置
    • 适用于需要虚拟机作为网络服务提供者的场景,如 Web 服务器、数据库服务器等
  • 缺点
    • 需要局域网中有足够的 IP 地址分配给虚拟机
    • 配置稍微复杂,需要了解主机的网络接口情况

内部网络:虚拟机之间的独立网络

内部网络是一种特殊的网络模式,它允许多个虚拟机在一个独立的网络中互相通信,但不与主机或局域网设备通信。这种模式特别适用于创建隔离的测试环境

  • 配置步骤
    • 打开 VirtualBox,选择目标虚拟机,点击“设置”
    • 进入“网络”选项卡,确保“启用网络适配器”已选中
    • 网络连接方式选择“内部网络”
    • 在“名称”字段中输入一个内部网络名称,确保所有需要互通的虚拟机使用相同的网络名称
    • 启动虚拟机,根据需求手动配置 IP 地址,确保在同一网段内
  • 优点
    • 虚拟机之间可以相互通信,适用于创建独立的测试环境
    • 不受主机或局域网的网络配置影响
  • 缺点
    • 虚拟机无法访问互联网或主机网络
    • 需要手动配置 IP 地址,可能对网络配置的理解有一定要求

主机专用网络:虚拟机与主机的独立网络

主机专用网络是一种介于 NAT 和内部网络之间的模式,它允许虚拟机与主机在一个独立的网络中通信,但不与其他局域网设备通信。这种模式适用于需要虚拟机与主机直接通信,但不需要外部网络访问的场景

  • 配置步骤
    • 打开 VirtualBox,选择目标虚拟机,点击“设置”
    • 进入“网络”选项卡,确保“启用网络适配器”已选中
    • 网络连接方式选择“主机专用适配器”
    • 启动虚拟机,虚拟机将自动获取一个主机专用网络的 IP 地址
  • 优点
    • 虚拟机与主机可以直接通信,适用于开发和测试环境
    • 不受局域网配置影响,安全性较高
  • 缺点
    • 虚拟机无法访问互联网或局域网中的其他设备
    • 需要手动配置主机专用网络的设置

自动驾驶工具工作记录
https://silhouettesforyou.github.io/2024/08/20/dde743d413c4/
Author
Xiaoming
Posted on
August 20, 2024
Licensed under