Linux:进程(环境变量、程序地址空间)

news2024/12/16 18:18:46

目录

冯诺依曼体系结构

操作系统

设计操作系统的目的 

操作系统的管理

进程

PCB

fork

进程状态

进程状态查看

僵尸进程

孤儿进程 

进程优先级 

查看、修改进程优先级命令

竞争、独立、并行、并发

进程切换

活动队列和运行队列 

活动队列

过期队列

active指针和expired指针 

环境变量 

查看环境变量

相关指令 

环境变量的组织方式

代码获取环境变量

程序地址空间

写时拷贝

mm_struct

为什么要有虚拟地址空间? 

进程终止

_exit函数

exit函数

进程等待 

wait

waitpid

进程程序替换


冯诺依曼体系结构

我们常见的计算机、服务器等大多数都遵守冯诺依曼体系

输入设备:键盘、鼠标、摄像头、话筒、网卡、扫描仪等

输出设备:显示器、磁盘、网卡、打印机等

中央处理器(CPU):含有运算器和控制器等

存储器:内存

关于冯诺依曼:

不考虑特殊情况;所有设备都只能和内存打交道


正是因为有了冯诺依曼体系,让当代计算机成为了性价比的产物

一般存储设备

如CPU:存储量小,访问效率快,成本高

如磁盘:存储量大,访问效率相对较慢,成本低

所以有了内存这个中存储,中速度来调节二者,从而让计算机速度更快

如果不考虑经济问题当然可以全部都用CPU级别的速度来造计算机,正是因此冯诺依曼让当代计算机成为了性价比的产物

操作系统

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)

操作系统是一个管理软硬件资源的软件

操作系统包括:
内核(进程管理,内存管理,文件管理,驱动管理)
其他程序(函数库,shell程序等等)

设计操作系统的目的 

对下:与硬件交互,管理所有的软硬件资源

对上:为软件(应用程序)提供一个良好的执行环境


  • 软硬件体系结构是层状结构
  • 访问操作系统必须使用系统调用(就是函数,只不过是系统提供的函数)
  • 只要一个程序访问了硬件,那么它就必须贯穿整个软硬件体系结构

操作系统不相信任何用户,但我们之所以使用它是因为它会暴露自己的部分接口(系统调用),供上层开发者使用

操作系统的管理

先描述,再组织

例如要对硬件进行管理

我们可以先对硬件进行描述
用一个结构体struct将各个信息进行描述到结构体中

再组织:
用我们学习过的数据结构将n个结构体变量组织起来
具体选择哪个数据结构需要根据实际情况考虑,查找可以使用哈希表,快速插入删除可以使用链表

进程

概念:程序的一个执行实例,正在执行的程序等

内核: 担当分配系统资源(CPU时间,内存)的实体

PCB

进程信息被放在一个进程控制块的数据结构中,是进程属性的结合,我们称之为PCB,Linux操作系统下的PCB是:task_struct

Linux中进程控制块PCB-------task_struct结构体结构 - 童嫣 - 博客园

在Linux中描述进程的结构体叫做task_struct

task_struct是Linux内核的一种数据结构,它会被装在到RAM(内存)里并且包含着进程的信息

  • 标⽰符: 描述本进程的唯⼀标⽰符,⽤来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器: 程序中即将被执⾏的下⼀条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  • 上下⽂数据: 进程执⾏时处理器的寄存器中的数据。
  • I∕O状态信息: 包括显⽰的I/O请求,分配给进程的I∕O设备和被进程使⽤的⽂件列表。
  • 记账信息: 可能包括处理器时间总和,使⽤的时钟数总和,时间限制,记账号等。
  • 其他信息

所有运行在系统里的进程都以task_struct链表的形式存在内核里


进程id:PID

父进程id:PPID

我们可以在代码中用getpid和getppid来查看当前进程的pid和ppid

它需要 sys/types.h 和 unistd.h两个头文件 

例如:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    printf("pid: %d\n", getpid());
    printf("ppid: %d\n", getppid());
    return 0;
}

这里可以看出当前进程运行后它的pid为32752,ppid为32488


查看进程 

进程信息可以通过/proc系统文件夹查看

这些蓝色的数字就是当前Linux系统下各个进程的pid

我们可以通过ps命令查看我们想要看的进程信息

ps ajx

作用是显示系统中所有用户的所有进程 

我们可以先把头第一行的头过滤出来,然后通过grep过滤专门来看我们想要查看的进程信息

// filename为文件名
ps ajx | head -1 && ps axj | grep filename
// pid为进程id
ps ajx | head -1 && ps axj | grep pid

我们也可以循环查看

// filename为文件名
while :; do ps ajx | head -1 && ps axj | grep filename; sleep 1; done
// pid为进程id
while :; do ps ajx | head -1 && ps axj | grep pid; sleep 1; done

fork

fork是一个系统调用

 

它的作用是创建一个子进程

fork有两个返回值

首先fork是有返回值的

在fork函数内部return之前就已经完成了子进程的创建,子进程会接着fork接下来的语句和父进程一起执行,所以就出现了一句代码有两个返回值的情况

如果是父进程,则返回值为子进程的pid

如果是子进程,则返回值为0

若fork出错,则返回负数


父子进程代码共享,数据各自开辟一份,私有一份(采用写时拷贝)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int ret = fork();
    printf("hello proc : %d!, ret: %d\n", getpid(), ret);
    sleep(1);
    return 0;
}

这里的printf语句执行了两次,足以证明有两个进程同时执行了这个printf语句

 fork之后我们可以利用返回值进行用if语句进行分流

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int ret = fork();
    if(ret < 0) // 出错
    {
        perror("fork");
        return 1;
    }
    else if(ret == 0) //child
    {    
        printf("I am child : %d!, ret: %d\n", getpid(), ret);
    }
    else //father
    { 
        printf("I am father : %d!, ret: %d\n", getpid(), ret);
    }

    return 0;
}

进程状态

一个进程在运行时可能会有多种状态

static const char* const task_state_array[] = {
	"R (running)", /*0 */
	"S (sleeping)", /*1 */
	"D (disk sleep)", /*2 */
	"T (stopped)", /*4 */
	"t (tracing stop)", /*8 */
	"X (dead)", /*16 */
	"Z (zombie)", /*32 */
};

R运行状态(running):表明进程要么是在运行中,要么在运行队列里

S睡眠状态(sleeping):意味着进程在等待事件完成(也叫做可中断睡眠状态)

D磁盘休眠状态(Disk sleep):也叫做不可中断睡眠状态,在这个状态的进程通常会等待IO的结束

T停止状态(stopped):可以通过发送SIGSTOP信号给进程来停止T状态下的进程。这个进程可以通过发送SIGCONT信号让进程继续运行

X死亡状态(dead):这个状态只是一个返回状态,不会在任务列表中看到这个状态

Z僵死状态(Zombies):当进程退出并父进程没有读取到子进程退出的返回代码就会产生僵死进程

进程状态查看

ps aux / ps axj 命令
  • a:显⽰⼀个终端所有的进程,包括其他用户的进程。
  • x:显⽰没有控制终端的进程,例如后台运⾏的守护进程。
  • j:显⽰进程归属的进程组ID、会话ID、⽗进程ID,以及与作业控制相关的信息
  • u:以用户为中⼼的格式显⽰进程信息,提供进程的详细信息,如用户、CPU和内存使⽤情况等

僵尸进程

只要子进程还在退出,父进程还在运行,并且父进程也没有读取子进程的状态,则子进程进入Z状态,成为僵尸进程

僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码

如果父进程一直不回收子进程,就会造成内存资源的浪费,因为它的PCB资源需要一直维护,C中定义一个结构体变量也是需要占用内存的

孤儿进程 

如果父进程先退出,那么这个子进程就称为孤儿进程

孤儿进程会被1号init进程领养,被1号进程回收

进程优先级 

cpu资源分配的先后顺序,就是指进程的优先权

ps -l

使用该命令可以查看系统进程信息

UID:代表执行者的身份

PID:代表进程的代号

PPID:代表父进程的代号

PRI:代表这个进程可被执行的优先级,值越小越早被执行

NI:代表这个进程的nice值

nice值表示进程可被执行的优先级的修正数值

PRI(new) = PRI(old) + nice

当这个PRI(new)越小就会越早被执行

所以,调整进程优先级,就是调整进程的nice值

nice值的取值范围是-20 ~ 19,一共40个级别

查看、修改进程优先级命令

先用top可以查看各进程的优先级

进入top后按 "r" ,输入进程pid,输入nice值即可完成修改优先级

也可以使用nice,renice命令、系统调用调整优先级

竞争、独立、并行、并发

竞争性:系统进程数目众多,而CPU资源只有少量,甚⾄1个,所以进程之间是具有竞争属性的。
为了⾼效完成任务,更合理竞争相关资源,便具有了优先级
独⽴性:多进程运行,需要独享各种资源,多进程运行期间互不⼲扰
并行:多个进程在多个CPU下分别,同时进行运行,这称之为并行
并发:多个进程在⼀个CPU下采⽤进程切换的⽅式,在⼀段时间之内,让多个进程都得以推进,称之为并发

进程切换

一个进程一旦占有了CPU,它的运行时间是有限的,这个时间可以叫做时间片

时间片:当代计算机都是分时操作系统,没有进程都有它合适的时间片(其实就是⼀个计数
器)。时间片到达,进程就被操作系统从CPU中剥离下来。

当进程切换的时候,操作系统会保存进程的上下文数据,当下一次轮到该进程运行时再将该数据恢复

保存到了task_struct里

活动队列和运行队列 

活动队列

时间片还没有结束的所有进程都按照优先级放在活动队列

nr_active:总共有多少个运行状态的进程

queue[140]:一个元素就是一个进程队列,下标就是优先级,相同优先级按照FIFO规则进行排队调度

bitmap[5]:为了提高查找非空队列的效率,用5*32个比特位表示队列是否为空,5*32 > 140可以表示每一个下标是否为空

过期队列

过期队列和活动队列的结构一模一样

过期队列上放置的进程都是时间片耗尽的进程

当活动队列上的进程都被处理完毕后,对过期队列的进程进行时间片重新计算(过期队列变活动队列,活动队列变过期队列)

active指针和expired指针 

active指针永远指向活动队列,expired指针永远指向过期队列

所以当活动队列的进程都被处理完毕后, 过期队列变活动队列,活动队列变过期队列的本质就是交换active和expired指针

环境变量 

环境变量一般指在操作系统中用来指定操作系统运行环境的一些参数

我们在编写代码的时候,链接时,从来都不知道我们所链接的动静态库在哪,但是照样可以链接成功,原因就是因为有相关环境变量帮助编译器进行查找

查看环境变量

env查看全部环境变量

echo $NAME(NAME是指定环境变量的名称)

相关指令 

echo $NAME:显示某个环境变量值

export:设置一个新的环境变量

env:显示所有环境变量

unset:清楚环境变量

set:显示本地定义的shell变量和环境变量

环境变量的组织方式

每个程序都会收到一张环境变量表,环境表是一个字符指针数组,每个指针指向一个以'\0'为结尾的环境字符串

代码获取环境变量

1. 命令行第三个参数 

#include <stdio.h>

int main(int argc, char *argv[], char *env[])
{
    int i = 0;
    for(; env[i]; i++)
    {
        printf("%s\n", env[i]);
    }
    return 0;
}

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

#include <stdio.h>

int main(int argc, char *argv[])
{
    extern char **environ;
    int i = 0;
    for(; environ[i]; i++)
    {
        printf("%s\n", environ[i]);
    }
    return 0;
}

libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明

3. 通过系统调用获取环境变量

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

int main()
{
    printf("%s\n", getenv("PATH"));
    return 0;
}

程序地址空间

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

int g_val = 0;

int main()
{
    pid_t id = fork();
    if(id < 0){
        perror("fork");
        return 0;
    }
    else if(id == 0){ //child
        g_val = 100;
        printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }else{ //parent
        printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
    sleep(1);
    return 0;
}

当我们执行上面的代码时,我们会存在一对父子进程

但是我们在子进程将g_val的值改成100时,父进程的g_val没有任何变化,说明了进程的独立性

但是它们的g_val的地址却一样的?地址一样值却不相同,能说明:

  • 变量内容不一样,父子进程输出的变量绝对不是同一个变量
  • 地址值一样,说明绝对不是物理地址

我们在用C/C++语言所看到的地址,全部都是虚拟地址,物理地址用户都看不到,由操作系统OS同一管理

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

每个进程都有自己独立的虚拟地址空间

操作系统会通过物理内存对虚拟地址空间在页表中进行映射关系,这样就能通过页表找到该存放的物理内存

所以即使两个程序的虚拟地址相同,但通过页表映射后它们对应的物理内存空间的地址是不一样的,所以就会出现虚拟地址相同但值不同的情况

写时拷贝

父子进程的代码共享,父子不再写入时,数据也是共享的,当任意一方试图写入时,便以写时拷贝的方式各自一份副本 

 因为有写时拷贝技术的存在,所以父子进程得以彻底分离,保证了进程的独立性

mm_struct

描述Linux下进程的地址空间的所有信息的结构体都是mm_struct(内存描述符)

 mm_struct结构是对整个用户空间的描述,每一个进程都会有自己独立的mm_struct,这样每一个进程都会有自己独立的地址空间能够互不干扰

为什么要有虚拟地址空间? 

如果没有虚拟地址空间,那进程就是直接在物理内存中操作

1. 安全风险

每个进程都可以访问任意的内存空间,这也就意味着任意一个进程都能够读写系统相关内存区域,如果是一个木马病毒,就能直接让设备瘫痪

2. 地址不确定

当运行时直接使用物理地址,我们无法确定内存现在使用到了哪里,也就是说拷贝的实际内存地址每一次运行都是不确定的

3. 效率低下 

如果直接使用物理地址,出现物理内存不够用的情况,我们一般是将不常用的进程拷贝到磁盘的交换分区中腾出内存,如果是物理地址的话就需要整个进程一起拷走这样时长太高

进程终止

进程终止的本质是释放系统资源,就是释放进程申请的相关内核数据结构和对应的数据和代码

进程退出我们可以通过 echo $? 查看进程退出码

_exit函数

#include <unistd.h>
void _exit(int status);

status定义了进程的终止状态,父进程通过wait来获取该值 

_exit是系统调用,它刷新的是系统级缓冲区 

exit函数

#include <unistd.h>
void exit(int status);

exit最后也会调用_exit函数,但在调用_exit之前,还做了其他工作

关闭所有打开的流,所有在应用层级的缓存数据均被写入

最后调用_exit函数

进程等待 

wait

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int* status);

成功则返回被等待进程的pid,失败则返回-1

参数是个输出型参数,可以获取子进程的退出状态,不关心可以设置为NULL

调用wait的父进程会随机等待任意一个子进程

waitpid

pid_ t waitpid(pid_t pid, int *status, int options);

成功则返回被等待进程的pid,失败则返回-1,如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0

参数:

pid表示需要等待的子进程,若为-1则表示等待任意一个子进程,与wait等效

status输出型参数,WIFEXITED:若为正常终止子进程返回的状态,则为真(查看进程是否正常退出),WEXITSTATUS:若WIFEXITED非零,提取子进程退出码(查看进程的退出码)

options:默认为0,表示阻塞等待。WNOHANG:若pid指定的子进程没有结束,则waitpid函数返回0,不予等待。若正常结束,则返回该子进程的ID


status参数不能简单的当作整形来看待,可以当作位图来看待

若正常退出,低7位比特位为0,8-15表示退出状态

若异常退出,低7位表示终止进程的信号,这时候的退出码则毫无意义

进程程序替换

fork之后,父子进程会执行同一个程序,但是我们也可以通过程序替换让子进程执行其他程序的代码

子进程往往要调用一种exec函数以执行另一个程序,当用户执行一种exec函数时,该进程的用户空间代码和数据会被新进程替换,从新进程启动例程开始执行

调用exec并不创建新进程,所以进程id不会改变

#include <unistd.h>

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

返回值:

调用出错则返回-1,成功直接执行新代码,没有成功返回值

这些函数非常多,但是只要掌握了命名风格就很容易记住了,除了exec之外,还有l、p、e、v,分别具有不同含义

  • l(list):表示参数采用列表
  • v(vector):参数用数组
  • p(path):有p自动搜索环境变量PATH
  • e(env):表示自己维护环境变量

#include <unistd.h>

int main()
{
    char *const argv[] = {"ps", "-ef", NULL};
    char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};

    execl("/bin/ps", "ps", "-ef", NULL);
    // 带p的,可以使⽤环境变量PATH,⽆需写全路径
    execlp("ps", "ps", "-ef", NULL);
    // 带e的,需要⾃⼰组装环境变量
    execle("ps", "ps", "-ef", NULL, envp);
    execv("/bin/ps", argv);
    // 带p的,可以使⽤环境变量PATH,⽆需写全路径
    execvp("ps", argv);
    // 带e的,需要⾃⼰组装环境变量
    execve("/bin/ps", argv, envp);

    exit(0);
}

这些函数中,只有execve是系统调用,其它的五个函数最终都是调用的execve


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

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

相关文章

希迪智驾持续亏损8.2亿:毛利率下滑,冲刺“自动驾驶矿卡第一股”

《港湾商业观察》黄懿 近日&#xff0c;希迪智驾&#xff08;湖南&#xff09;股份有限公司&#xff08;下称“希迪智驾”&#xff09;向港交所主板递交上市申请&#xff0c;联席保荐人为中金公司、中信建投国际、中国平安资本&#xff08;香港&#xff09;。 资料显示&#…

Rust之抽空学习系列(三)—— 编程通用概念(中)

Rust之抽空学习系列&#xff08;三&#xff09;—— 编程通用概念&#xff08;中&#xff09; 1、变量&可变性 在Rust中&#xff0c;变量默认是不可变的 fn main() {let x 5;println!("x is {}", x); }使用let来声明一个变量&#xff0c;此时变量默认是不可变…

OpenCV中的识别图片颜色并绘制轮廓

一、实验原理 使用OpenCV库在图像中识别和绘制特定颜色&#xff08;黄色&#xff09;的轮廓 二、实验代码 import cv2 import numpy as np# 读取图片并调整大小 img cv2.imread(./color_1.png) img cv2.resize(img,(600,600))# 将图片从BGR颜色空间转换到HSV颜色空间 img_h…

【Qt】qt基础

目录 一、使用Qt Creator创建qt项目 二、项目文件解析 三、Qt中创建图形化界面的程序的两种方法 四、对象树 五、Qt中处理打印乱码问题的利器&#xff1a;qDebug() 一、使用Qt Creator创建qt项目 1.选择项目模板 选中第一类模板Application(Qt应用程序&#xff0c;包含普…

Transformer入门(6)Transformer编码器的前馈网络、加法和归一化模块

文章目录 7.前馈网络8.加法和归一化组件9.组合所有编码器组件构成完整编码器 7.前馈网络 编码器块中的前馈网络子层如下图所示&#xff1a; 图1.32 – 编码器块 前馈网络由两个带有ReLU激活函数的全连接层组成。全连接层&#xff08;Fully Connected Layer&#xff09;有时也…

AI智算-k8s部署大语言模型管理工具Ollama

文章目录 简介k8s部署OllamaOpen WebUI访问Open-WebUI 简介 Github&#xff1a;https://github.com/ollama/ollama 官网&#xff1a;https://ollama.com/ API&#xff1a;https://github.com/ollama/ollama/blob/main/docs/api.md Ollama 是一个基于 Go 语言开发的可以本地运…

HTML/CSS总结

HTML 1.1 标题标签h 为了使网页更具有语义化&#xff0c;我们经常会在页面中用到标题标签&#xff0c;HTML提供了6个等级的标题&#xff0c;即 标题标签语义&#xff1a; 作为标题使用&#xff0c;并且依据重要性递减 其基本语法格式如下&#xff1a; <h1> 标题文本…

信号处理:概念、技术、领域

目录 基本概念 主要技术 应用领域 信号处理是一个涉及分析、修改和再生信号的多学科领域。信号可以是各种形式的&#xff0c;例如声音、图像、视频或其他类型的监测数据。信号处理的主要目标是提取有用的信息并增强信号的质量。以下是信号处理的一些基本概念和应用&#xff…

黑盒白盒测试

任务1 黑盒测试之等价类划分法 【任务需求】 【问题】例&#xff1a;某报表处理系统要求用户输入处理报表的日期&#xff0c;日期限制在2003年1月至2008年12月&#xff0c;即系统只能对该段期间内的报表进行处理&#xff0c;如日期不在此范围内&#xff0c;则显示输入错误信息…

深度学习物体检测之YOLOV5源码解读

V5比前面版本偏工程化,项目化,更贴合实战 一.V5版本项目配置 (1)整体项目概述 首先github直接查找yolov5&#xff0c;下载下来即可。在训练时&#xff0c;数据是怎么处理的&#xff1f;网络模型架构是怎么设计的(如各层的设计)&#xff1f;yolov5要求是大于python3.8与大于等…

Go 怎么做性能优化芝麻开门篇

一、性能优化的流程 我们在对某个功能&#xff08;或单个接口&#xff09;做性能优化的时候。一般是该功能&#xff08;或接口&#xff09;性能无法满足我们的业务要求&#xff0c;所以被迫优化。在开始优化之前&#xff0c;我们需要明白一些理论知识。 1、常见的性能优化指标…

【Elasticsearch入门到落地】4、Elasticsearch的安装

接上篇《3、es与mysql的概念对比》 上一篇我们学习了Elasticsearch与Mysql的概念与区别。本篇我们来进行Elasticsearch的环境准备及软件安装。 一、环境准备 如果我们没有自己的Linux服务器&#xff0c;且现在正在使用的是Windows操作系统的电脑&#xff0c;那么首先我们需要安…

CRYPTO密码学

加解密算法/编码 哈希算法SM3SHA-3base家族GBGB18030GB2312GBKutf家族恺撒二进制分区法unicodeASCIIDSADSSCRC32校验对称非对称gbk编码h264SEA初探smc动态代码保护四方密码曼彻斯特编码剖析基本概念什么是编码?什么是加密与解密寻找银弹-有没有无法破解的密码通过Java代码入门…

我们来学mysql -- 探讨win安装方式(安装篇)

题记 书接上回&#xff0c;在我们来学mysql – 闲聊(安装篇)中&#xff0c;拿到安装包&#xff0c;当宝贝一样揣在怀里 然而&#xff0c;还没捂热乎&#xff0c;得粉丝秘报&#xff0c;U哥&#xff0c;上篇文章用了滞后的官方文档&#xff0c;哈哈哈…内心的小倔强&#xff0c…

pip 如何快速安装包

一、问题描述 当使用Python通过pip安装一些包时&#xff0c;pip默认是访问的国外的源&#xff0c;但在国内访问又是异常的慢&#xff0c;而且还经常因为网络问题导致安装失败&#xff0c;比如下面通过pip install jupyter来安装jupyter Notebook&#xff0c;这网速真的超级慢&…

CodeBook-Ubuntu-sandbox Linux 沙箱服务 docker pull

CodeBook-Ubuntu-sandbox Linux 沙箱服务 开源技术栏 这是一个多用户的 Linux SSH 服务沙箱&#xff0c;支持启动时动态加载用户列表&#xff0c;并可随时更新用户信息。每个用户仅能修改自己目录下的文件&#xff0c;确保了环境的安全性和隔离性。 目录 文章目录 CodeBook-…

【echarts】数据过多时可以左右滑动查看(可鼠标可滚动条)

1. 鼠标左右拖动 在和 series 同级的地方配置 dataZoom&#xff1a; dataZoom: [{type: inside, // inside 鼠标左右拖图表&#xff0c;滚轮缩放&#xff1b; slider 使用滑动条start: 0, // 左边的滑块位置&#xff0c;表示从 0 开始显示end: 60, // 右边的滑块位置&#xf…

【数据分享】2014-2024年我国POI兴趣点数据(免费获取/来源于OSM地图)

POI是Point of Interest的简称&#xff0c;意为“兴趣点”&#xff0c;是互联网电子地图中用于表示特定位置的地理实体的核心数据类型。POI通常用于标注具体地点&#xff0c;例如餐厅、商场、学校、医院、景点等。这些数据以点的形式呈现&#xff0c;并附带详细属性信息&#x…

使用html和JavaScript实现一个简易的物业管理系统

码实现了一个简易的物业管理系统&#xff0c;主要使用了以下技术和功能&#xff1a; 1.主要技术 使用的技术&#xff1a; HTML: 用于构建网页的基本结构。包括表单、表格、按钮等元素。 CSS: 用于美化网页的外观和布局。设置字体、颜色、边距、对齐方式等样式。 JavaScript…

SSM 垃圾分类系统——高效分类的科技保障

第五章 系统功能实现 5.1管理员登录 管理员登录&#xff0c;通过填写用户名、密码、角色等信息&#xff0c;输入完成后选择登录即可进入垃圾分类系统&#xff0c;如图5-1所示。 图5-1管理员登录界面图 5.2管理员功能实现 5.2.1 用户管理 管理员对用户管理进行填写账号、姓名、…