七、进程地址空间

news2024/11/24 13:32:27

一、环境变量

(一)概念

环境变量(environment variables):系统当中用做特殊用途的系统变量。
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
子进程默认会复制拥有与父进程相同的环境变量。

(二)常见环境变量

PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。

(三)查看环境变量方法

echo $NAME NAME:你的环境变量名称
指令 env——显示所有环境变量

(四)和环境变量相关的命令

echo: 显示某个环境变量值
export: 设置一个新的环境变量(export aaaa)
env: 显示所有环境变量
unset: 清除环境变量(rm只是普通的文件操作指令,无法删除环境变量)
set: 显示本地定义的shell变量(本地变量)和环境变量

1.echo: 显示某个环境变量值
2.export : 导出环境变量
3.env : 显示所有环境变量
4.unset :删除环境变量
5.set:查看本地定义的shell变量(本地变量)和环境变量
在这里插入图片描述

(五)和环境变量相关的命令

基本指令也是程序,为什么我们的代码程序运行要带路径,而系统的指令不用带路径?
比如使用指令ls,pwd时直接使用即可,使用自己的myproc 可执行程序时(gcc -o mproc.c myproc) 需要./myproc.c
答:系统中是存在相关的环境变量,保存了程序的搜索路径的! 比如:执行 ls 这个可执行程序时,系统会在PATH中一个一个搜索,在特定路径(系统所有命令都在usr/bin路径下)下可以找到ls,就可以执行。
系统中搜索可执行程序的环境变量叫做 PATH !

1.如何让自己的程序不带路径也可以执行?

把自己的程序拷贝进环境变量中,就可以直接myproc执行程序了,拷贝的过程就是安装软件,但是不建议这样做,本身我们的软件就没什么意义,会污染系统,删除=卸载。
把myproc自己的文件加入环境变量PATH中,export PATH=$PATH:路径(相当于把PATH中的路径改成PATH和myproc的路径)。
错误示范:如果直接 export PATH=路径 ,会覆盖环境变量PATH的原有路径:这里pwd还能用,ls,top什么的就不能用了

# 二、常见的环境变量
XDG_SESSION_ID=299733
TERM_PROGRAM=vscode
HOSTNAME=VM-24-7-centos
TERM=xterm-256color
SHELL=/bin/bash  : 显示shell所在路径
HISTSIZE=3000 : 历史能够记录自己敲过的命令条数
SSH_CLIENT=111.18.128.241 7177 22 : ip地址
TERM_PROGRAM_VERSION=1.78.2 : 版本
USER=root/ : 用户名
VSCODE_GIT_ASKPASS_MAIN=/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/extensions/git/dist/askpass-main.js
LOGNAME=root
MAIL=/var/spool/mail/root
PWD=/root/new/add.ringqueue  : PWD:当前用户所处路径
LANG=en_US.utf8 : 支持的编码格式,现在支持的是UTF8
VSCODE_GIT_ASKPASS_EXTRA_ARGS=
HOME=/root  :代表不同用户的家目录
SHLVL=5
VSCODE_GIT_IPC_HANDLE=/run/user/0/vscode-git-d20790e3d3.sock
SSH_CONNECTION=111.18.128.241 7177 10.0.24.7 22
VSCODE_IPC_HOOK_CLI=/run/user/0/vscode-ipc-729d4afb-0a8a-48d3-848b-da318c83e93a.sock
LESSOPEN=||/usr/bin/lesspipe.sh %s
BROWSER=/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/bin/helpers/browser.sh
PROMPT_COMMAND=__vsc_prompt_cmd_original
VSCODE_GIT_ASKPASS_NODE=/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/node
GIT_ASKPASS=/root/.vscode-server/bin/b3e4e68a0bc097f0ae7907b217c1119af9e03435/extensions/git/dist/askpass.sh
XDG_RUNTIME_DIR=/run/user/0
HISTTIMEFORMAT=%F %T 
COLORTERM=truecolor
OLDPWD=/root/new
_=/usr/bin/env

(一)HOSTNAME——显示主机名

[root@VM-24-7-centos add.ringqueue]# echo $HOSTNAME
VM-24-7-centos

(二)SHELL—— 显示shell所在路径

(三)HISTSIZE——历史能够记录自己敲过的命令条数

(四)HOME——代表不同用户的家目录

三、环境变量和局部(普通)变量

环境变量:系统当中用做特殊用途的系统变量。
命令行变量分两种:

(一)普通变量(在env查不到)

(二)环境变量(全局)(在env能查到)

环境变量具有全局属性:环境变量是会被子进程继承下去的! !
所谓得本地变量,本质就是在bash内部定义的变量,不会被子进程继承下去!

四、环境变量的C、C++获取方式

(一)问题1:main函数可以带参数吗?最多可以带多少?

可以,实际是三个。

1. 先说main函数的前两个参数

main函数的前两个参数分别是下图所示:这两个参数我们称为:命令行参数
int main(int argc,char *argv[]) { // 数组个数 数组

}

2.argv[]中放什么呢?

我们给main函数传递的前两个参数 argc,char* argv[] 称为 命令行参数,传递的是命令行中输入的程序名和选项!比如命令行输入了./myproc -a -b -c,argc对应就是4,argv[ ] 中传入了这4个字符串,argv[0] = “./myproc”,argv[1] = “-a”,argv[2] = “-b”,argv[3] = “-c”,argv[4] = “NULL”,指针数组以NULL结尾。

在这里插入图片描述
给命令行参数传程序名和选项意义是什么?我们通过实现一个命令行版的计算器来理解:

(二)实现一个命令行版的计算器

我们要实现的功能:
执行 ./myproc -a 10 20 要实现 10+20=30;
执行 ./myproc -s 10 20 要实现 10-20=-10

// makefile
myproc:myproc.c
    g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
    rm -f myproc
// main.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
 
int main(int argc,char *argv[])
{
    if (argc != 4)
    {
        //如果用户输入不对,打印使用手册,-a加法,-s(subtract)减法,-m乘法,-d除法:
        printf("Usage: %s [-a|-s|-m|-d] one_data two_data\n", argv[0]);
        return 0;
    }
    int x = atoi(argv[2]);    //atoi:把字符串转为整数
    int y = atoi(argv[3]);
    if (strcmp("-a", argv[1]) == 0)    //如果输入-a,就是加法
    {
        printf("%d+%d=%d\n", x, y, x + y);
    }
    else if (strcmp("-s", argv[1]) == 0)    //如果输入-s,就是减法
    {
        printf("%d-%d=%d\n", x, y, x - y);
    }
    else if (strcmp("-m", argv[1]) == 0)    //如果输入-m,就是乘法
    {
        printf("%d*%d=%d\n", x, y, x * y);
    }
    else if (strcmp("-d", argv[1]) == 0 && y != 0)    //如果输入-d,就是除法
    {
        printf("%d/%d=%d\n", x, y, x / y);
    }
    else
    {
        //输入错误说明不会用,还是打印使用手册
        printf("Usage: %s [-a|-s|-m|-d] one_data two_data\n", argv[0]);
    }
 
    return 0;
}

在这里插入图片描述

1.给命令行参数传程序名和选项意义是什么?

答:同一个程序,通过传递不同的参数,让同一个程序有不同的执行逻辑 / 执行结果。
这就解释了指令中那么多选项的由来和起作用的方式!!Linux系统中,会根据不通的选项,让不同的命令,可以有不同的表现!
这就解释了我们平时输入的指令传入了哪里!

(三)命令行可以带第三个参数!: char *env[](环境变量)

1.每个进程是会被传入环境变量参数的,环境变量传给env[] 。

#include<stdio.h>
int main(int argc,char* argv[],char* env[])
{
// 存环境变量的指针数组以NULL结尾,所以到NULL时for循环结束:
for(int i=0;env[i];i++)
{
printf(“env[%d]:%s\n”,i,env[i]);
}
return 0;
}
在这里插入图片描述

2.C语言中函数无参,也是可以传参的,只不过实参没用上

但是如果是int fun(void) 就不可以传参。
这就解释了我们可以直接给main()函数传参的原因

(四)通过代码获取环境变量的三种方式

1.C语言获取环境变量的第一种方法

#include<stdio.h>
int main(int argc,char* argv[],char* env[])
{
// 存环境变量的指针数组以NULL结尾,所以到NULL时for循环结束:
    for(int i=0;env[i];i++) 
{
    printf("env[%d]:%s\n",i,env[i]);                                                                                
     }
return 0;
}

在这里插入图片描述

2.通过第三方变量environ获取

C语言给我们提供了一个全局变量environ。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main() {
    extern char** environ;

    for (int i = 0; environ[i]; i ++)  {
        printf("%d : %s \n",i,environ[i]);
    }
    return 0;
}

3.getenv——获取环境变量的接口

通过环境变量名直接获得环境变量的内容。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main() {
    char *val = getenv("PATH");
    printf("%s\n",val);
    return 0;
}

在这里插入图片描述

五、程序地址空间

(一)概念

程序地址空间,不是内存!
程序地址空间=进程地址空间,是操作系统上的概念!
堆,栈相对而生。
堆区向地址增大方向增长
栈区向地址减少方向增长
我们一般在C函数中定义的变量,通常在栈上保存,那么先定义的一定是地址比较高的 !

如何理解static变量?
函数内定义的变量用static修饰,本质是编译器会把该变量编译进全局数据区!

(二)感知地址空间的存在

函数内定义的变量用static修饰,本质是编译器会把该变量编译进全局数据区! 父子进程共享全局变量。

#include<unistd.h>
#include<cstdio>
int g_val = 100;
int main() {
    pid_t id = fork();
    if (id == 0) {
        int flag = 0;
        while (true) {
            printf("i am son : %d, ppid : %d, g_val : %d, &g_val : %p\n\n",getpid(),getppid(),g_val,&g_val);
            sleep(1);
            flag ++;
            if (flag == 5) {
                g_val = 200;
                printf("全局数据我已经改了,请你注意查看\n");
            }
        }
    }
    else {
        while(true) {
             printf("i am father : %d, ppid : %d, g_val : %d, &g_val : %p\n\n",getpid(),getppid(),g_val,&g_val);
             sleep(2);  
        }
    }
    return 0;
}

fork创建子进程,父子进程同时运行,若在子进程中第5秒改了全局变量g_val的值,会发现!
在这里插入图片描述

父子进程读取同一个变量(因为地址一样!),但是子进程修改的全局变量后,父子进程读取到的
内容却不一样! ! ! !
结论:

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量。
  • 但地址值是一样的,说明,该地址绝对不是物理地址!
  • 在Linux地址下,这种地址叫做虚拟地址。
  • 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理。

OS必须负责将虚拟地址转化成物理地址 !

(三)让每一个进程都认为自己是独占系统中的所有资源

进程地址空间:每一个进程在启动的时候,都会让操作系统给他创建一个地址空间,该地址空间就是进程地址空间

每一个进程,都会有一个自已的进程地址空间!
操作系统要不要管理这些进程地址空间呢??
先描述,在组织
进程地址空间,其实是内核的一个数据结构,struct mm_ struct (稍后看! )
举例子理解:

  • 我们往银行存10亿,但是银行可能没10亿,但银行给你画的饼就是10个亿。
  • 一个富豪有3个私生子,富豪给每个私生子画的大饼,说自己有10个亿以后都是你的财产
  • 大富豪: OS
    三个私生子:进程
    富翁给三个私生子画的大饼:进程地址空间
    我不给你,但是我这么说,让你感觉我给你!
    让每一个进程都认为自己是独占系统中的所有资源的! !

(四)虚拟地址空间=进程地址空间:struct mm_ struct

1.概念

所谓的进程/虚拟地址空间:其实就是OS通过软件的方式,给进程提供一个软件视角,认为自己会独占系统的所有资源(内存)。
每个进程会维护一个mm_struct,虚拟地址和物理内存通过页表建立映射关系。(上学时,一个班级中,老师点名需要一张名单,这个名单就是虚拟地址空间)
定义:就是从进程的视角看到的地址空间,是进程运行时所用到的虚拟地址的集合,地址最大的作用是唯一性。

我们在语言层面遇到的地址都是虚拟地址!每个进程都有一个地址空间,都认为自己独占物理内存。

linux下:逻辑地址=虚拟地址=线性地址。

2.为什么不让PCB直接去访问物理地址

  • task_struct如果可以直接访问物理地址,但是物理地址有很多进程,如果你不小心寻址错误,访问到了其他进程,而这个进程是转账类似的,那是不是很危险?而如果我们有一层中间层,不允许你直接访问物理地址,而是在这之间对你的请求进行检查,如果合法给你映射过去,不合法就中止你的请求。
  • 例子:就像const char* s=“hello world”,*s=‘H’,这样是不允许的,当页表识别出你是字符常量区的,它映射时就不会给你w的权限,本质上就是OS给你的权限只有r权限。
  • 每一个进程只隐射到合法内存,不会恶意进程访问,保护物理内存,可以更方便进程与进程之间的解耦,保证了独立性这样的特性。

4.为什么存在地址空间

  • 保护内存。如果进程之间可以访问物理内存,万一进程越界或者非法操作,不安全!
  • 进程管理-Linux内存管理。因为进程具有独立性,一个进程对被共享的数据做修改,如果影响了其他进程,不能称之为独立性,进程地址空间的存在,可以更方便的进行进程和进程的数据代码之间的解耦,保证了进程独立性这样的特征!
  • 让进程或者程序以统一的视角,来看待进程对应的代码和数据等各个区域,方便使用编译器也已统一的角度来进行编译代码!

4. 区域

每个区域范围,都是可以有对应的编号的,在虚拟地址空间 mm_struct 中有存储各个数据区的起始地址和结束地址,也就是区域。
在这里插入图片描述

5.写时拷贝

写时拷贝正好可以回答fork 现象,子进程修改的全局变量后,父子进程读取到的内容却不一样?

因为进程具有独立性,一个进程对被共享的数据做修改,如果影响了其他进程,不能称之为独立性,任何一方尝试写入,OS先进程数据拷贝,更改页表映射,然后让进程继续进行修改!!写时拷贝 : 操作系统自动做的!!(写时拷贝本身就是有OS的内存管理模块完成的!所以我们感知不到)。
在这里插入图片描述

写时拷贝:g_val会再拷贝一份,子进程中的映射关系会改变,指向新的g_val,但是g_val的虚拟地址(相对地址)还是原来的地址,和父进程的g_val虚拟地址(相对地址)一样,但是他们的物理地址不一样,100改成200时,只会改变新的g_val!

6.为什么要写时拷贝?

为什么要写时拷贝,创建子进程的时候,就把数据分开,不行吗?

  • 父进程的数据,子进程不一定全用,即便使用,也不一定全部写入——会有浪费空间的嫌疑
  • 最理想的情况,只有会被父子修改的数据,进行分离拷贝。不需要修改的共享即可——但是从技术角度实现复杂,不可能实现
  • 如果fork的时候,就无脑拷贝数据给子进程,会增加fork的成本(内存和时间)

所以最终采用写时拷贝:

  • 写时拷贝只会拷父子修改的,变相的,就是拷贝数据的最小成本
  • 拷贝的成本依旧存在
    **写时拷贝本质是延迟拷贝策略!**只有真正使用的时候,才给你!
    你想要,但是不立马使用的空间,先不给你,那么也就意味着可以先给别人!
    变相的提高内存的使用率!

7.fork有两个返回值,pid_ t id ,同一个变量,怎么会有不同的值?

  • 当一个函数准备return,return 会被执行两次,return 的本质,就是通过寄存器将返回值写入到接受返回值的变量中,其实在return之前,你的子进程已经创建好了,准备被调度了,所以,返回的本质就是写入,谁先返回,谁就先写入父进程和子进程各自执行return!

  • 当id=fork()的时候,谁先返回,谁就要发生写时拷贝,所以,同一个变量,会有不同的内容值,本质是因为大家的虚拟地址是一样的,但是大家对应的物理地址是不一样的! !

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

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

相关文章

深入理解深度学习——正则化(Regularization):Dropout

分类目录&#xff1a;《深入理解深度学习》总目录 Dropout供了正则化一大类模型的方法&#xff0c;计算方便且功能强大。在第一种近似下&#xff0c;Dropout可以被认为是集成大量深层神经网络的实用Bagging方法。Bagging涉及训练多个模型&#xff0c;并在每个测试样本上评估多个…

数组扁平化的8种方法 - js篇

文章目录 方式1&#xff1a;使用基础的递归遍历方式2&#xff1a;使用reduce函数递归遍历方式3&#xff1a;数组强制类型转换方式4&#xff1a;while循环结合findIndex与concat方式5&#xff1a;直接使用ES6的flat方法方式6&#xff1a;使用JSON的函数和正则表达式方式7&#x…

#【六·一】让代码创造童话,共建快乐世界# 庆祝儿童节的Html和Python代码

文章目录 1.儿童节的简介2.中国庆祝儿童节的方式3.一段庆祝儿童节的Python代码4.一段庆祝儿童节的Html代码 1.儿童节的简介 国际儿童节&#xff08;又称儿童节&#xff0c;International Children’s Day&#xff09;定于每年的6月1日。为了悼念1942年6月10日的利迪策惨案和全…

dvwa靶场通关(五)

第五关 File Upload&#xff08;文件上传漏洞&#xff09; File Upload&#xff0c;即文件上传漏洞&#xff0c;通常是由于对上传文件的类型、内容没有进行严格的过滤、检查&#xff0c;使得攻击者可以通过上传木马获取服务器的webshell权限 low low等级没有任何的防护 创建…

10 【组件编码流程 组件自定义事件 全局事件总线】

1.组件编码流程 组件化编码流程&#xff1a; ​ (1).拆分静态组件&#xff1a;组件要按照功能点拆分&#xff0c;命名不要与html元素冲突。 ​ (2).实现动态组件&#xff1a;考虑好数据的存放位置&#xff0c;数据是一个组件在用&#xff0c;还是一些组件在用&#xff1a; ​ 1…

将MSYS2 MinGW集成到Windows终端

微软开发了一款Windows终端的开源软件&#xff0c;非常好用。安装后在Win7及以上系统会在右键菜单中添加一条“在终端中打开”的命令&#xff0c;非常方便。它默认配置了Windows命令行以及PowerShell&#xff0c;如果安装了Visual Studio 2022还会配置Visual Studio 2022的命令…

C++入门教程||C++ Web 编程

C Web 编程 什么是 CGI&#xff1f; 公共网关接口&#xff08;CGI&#xff09;&#xff0c;是一套标准&#xff0c;定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。CGI 规范目前是由 NCSA 维护的&#xff0c;NCSA 定义 CGI 如下&#xff1a;公共网关接口&#xf…

《Java并发编程实战》课程笔记(十二)

CountDownLatch 和 CyclicBarrier&#xff1a;如何让多线程步调一致&#xff1f; 原始对账系统 对账系统的业务简化后&#xff1a; 首先用户通过在线商城下单&#xff0c;会生成电子订单&#xff0c;保存在订单库&#xff1b;之后物流会生成派送单给用户发货&#xff0c;派送…

软件测试面试怎样介绍自己的测试项目?会问到什么程度?

想知道面试时该怎样介绍测试项目&#xff1f;会问到什么程度&#xff1f;那就需要换位思考&#xff0c;思考HR在这个环节想知道什么。 HR在该环节普遍想获得的情报主要是下面这2个方面&#xff1a; 1&#xff09;应聘者的具体经验和技术能力&#xff0c; 2&#xff09;应聘者的…

【企业化部署】Tomcat部署及优化

文章目录 前言一、Tomcat 的概念1. Tomcat 核心组件1.1 什么是 servlet1.2 什么是 JSP 2. Tomcat 功能组件结构2.1 Container 结构分析 3. Tomcat 请求过程4. 配置文件4.1 安装目录4.2 conf 子目录 二、Tomcat 服务部署1. 下载并安装 JDK1.1 关闭防火墙&#xff0c;将安装 Tomc…

码垛机械臂工作站系统设计

码垛机械臂工作站系统设计 第一章 控制系统硬件设计1.1 引言1.2 控制系统总体方案1.3 控制系统硬件的选型1.3.1 可编程控制器的选型1.3.2 工业触摸屏的选型1.3.3 传感器的选型 1.4 硬件的接线与通讯1.4.1 可编程控制器的I/O分配与接线1.4.2 伺服电机驱动器的接线1.4.3 触摸屏与…

XML入库后空白字符丢失问题

最近项目上在做电子病历&#xff0c;使用的是第三方的电子病历组件&#xff0c;该病历组件是利用XML来组织数据的。界面上渲染出来的效果如下图&#xff1a; XML渲染后的界面 对应的后台数据&#xff08;已做简化处理&#xff09;是如下XML格式的&#xff0c;其中的空格部分是…

Windows 下配置Vitis HLS OpenCV仿真库(记录帖)

遇到的问题 我的配置&#xff1a; Vitis Vision 2022 opencv-4.4.0 vision Library 2022 Vitis HLS 2021.1 实测有BUG&#xff0c;编译好之后无法综合&#xff0c;别问我为什么知道 1. Download opencv_ffmpeg.dll 卡住 解决方法 打开 new_build 目录&#xff08;编译路径&…

从小白到大神之路之学习运维第33天——第三阶段——mysql数据库

第三阶段基础 时 间&#xff1a;2023年6月5日 参加人&#xff1a;全班人员 内 容&#xff1a; Mysql数据库 目录 前提环境配置&#xff1a; 一、CentOS 7 安装 MySQL 5.7 二、MySQL 操作示例&#xff1a; 三、MySQL 5.7远程登录 前提环境配置&#xff1a; 关闭防火…

微信如何批量添加好友?

现在营销中&#xff0c;微信已成为一种重要的沟通方式。微信目前是没有自动批量添加好友的功能&#xff0c;需要运营者一个一个手动去添加&#xff0c;这样太过于浪费时间&#xff0c;并且加频繁了还容易被封号&#xff0c;今天给大家介绍几种手动批量加好友的方式以及怎么借助…

人工智能和网络安全哪个好?一般人我还是劝你算了吧

人工智能门槛高&#xff0c;上限高 网络安全门槛低&#xff0c;下限低 但是以目前的行业内招聘需求来看网安缺hvv安服工具人和法学双修合规人&#xff0c;人工智能缺高端算法大牛。 一、从安全出发&#xff0c;然后去学习人工智能&#xff0c;最后走人工智能安全。 这个确实需…

Java网络通讯案例——即时通讯(控制台版)

一、需求分析 用户与用户之间1-1或1-n通讯 二、技术分析 &#xff08;一&#xff09;客户端 客户端的功能有两个&#xff1a;发消息和接消息发消息&#xff1a;使用Socket技术的流式输出&#xff0c;配合打印流封装发送。接信息&#xff1a;使用读取专用线程&#xff0c;搭配…

usmile笑容加新品发布,可视化定义电动牙刷未来发展路径?

历经20余年的发展&#xff0c;中国电动牙刷市场以外资品牌入华为肇始&#xff0c;到目前已经呈现出品牌林立、供给丰富&#xff0c;且国产品牌开始后来者居上的局面。 但近年来行业高速发展的势头似乎有所收敛&#xff0c;与此同时&#xff0c;市场还具备广阔的可拓展空间。数…

M.2 SSD接口详解

一、M.2简介 M.2接口是一种新的主机接口方案&#xff0c;可以兼容多种通信协议&#xff0c;如sata、PCIe、USB、HSIC、UART、SMBus等。 M.2接口是为超极本&#xff08;Ultrabook&#xff09;量身定做的新一代接口标准&#xff0c;以取代原来的mSATA接口。无论是更小巧的规格尺…

【Web服务应用】Tomcat部署

Tomcat部署 一、Tomcat简介二、tomcat组件2.1核心组件2.2Tomcat功能组件2.3Tomcat 请求过程 三、部署Tomcat服务3.1Tomcat虚拟主机配置 四、Tomcat多实例部署 一、Tomcat简介 一款 java 开发的开源的 Web 应用服务程序。 可以作为Web应用服务器&#xff0c;处理静态的Web页面&…