当前位置: 首页 > news >正文

【Linux】18.Linux进程控制(2)

文章目录

  • 3. 进程程序替换
    • 3.1 单进程版 -- 看看程序替换
    • 3.2 替换原理
    • 3.3 替换函数
      • 函数解释
      • 命名理解
    • 3.4 多进程版 -- 验证各种程序替换接口
    • 3.5 自定义shell


3. 进程程序替换

3.1 单进程版 – 看看程序替换

makefile

mycommand:mycommand.cgcc -o $@ $^ -std=c99
.PHONY:clean
clean:rm -f mycommand

mycommand.c

#include <stdio.h>
#include <unistd.h>// 提供execl, getpid等函数
#include <stdlib.h>int main(){// 打印exec调用前的进程信息// getpid(): 获取当前进程ID// getppid(): 获取父进程IDprintf("before: I am a process, pid:%d, ppid:%d\n",getpid(),getppid());//这类方法的标准写法// execl函数执行新程序// 参数1 "/usr/bin/ls": 要执行的程序的完整路径// 参数2 "ls": 程序名称(argv[0])// 参数3 "-a": 显示所有文件(包括隐藏文件)// 参数4 "-l": 使用长格式显示// 参数5 NULL: 参数列表结束标志execl("/usr/bin/ls","ls", "-a", "-l", NULL);// 如果exec执行成功,这行代码永远不会被执行// 因为原程序的内容已被ls程序替换printf("after: I am a process, pid:%d, ppid:%d\n",getpid(),getppid());return 0;
}

打印结果:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ ./mycommand
before: I am a process, pid:261495, ppid:261085
total 36
drwxrwxr-x  2 ydk_108 ydk_108  4096 Jan 20 22:26 .
drwxrwxr-x 13 ydk_108 ydk_108  4096 Jan 20 22:14 ..
-rw-rw-r--  1 ydk_108 ydk_108    82 Jan 20 22:16 makefile
-rwxrwxr-x  1 ydk_108 ydk_108 16832 Jan 20 22:26 mycommand
-rw-rw-r--  1 ydk_108 ydk_108   895 Jan 20 22:26 mycommand.c
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ 

这个程序被ls替换了。

5517839aada37f69f4be20daccba78a9

一开始这个进程有自己的数据段和代码段,ls有自己的数据段和代码段,但是这里ls直接把mycommand的进程的代码段和数据段在内存中覆盖了,进而把页表中的虚拟地址也更改了。

这个就叫做进程替换,也就是进程替换的基本原理。


3.2 替换原理

fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

d8d0749abcf16c6959fb7c5488ac5913


3.3 替换函数

其实有六种以exec开头的函数,统称exec函数:(这六个都是库函数调用接口,他们的区别只是传参的不同)

#include <unistd.h>int execl(const char *path, const char *arg, ...);// 第一个参数是完整路径,第二个参数通常是程序名
int execlp(const char *file, const char *arg, ...);//execlp自己会在默认的PATH系统的环境变量里面找,所以可以不带路径
int execle(const char *path, const char *arg, ...,char *const envp[]);// e 表示可以传递环境变量,最后一个参数是环境变量数组
int execv(const char *path, char *const argv[]);// v 表示参数以数组形式传递,比execl更适合参数数量不确定的情况
int execvp(const char *file, char *const argv[]);// 结合了v(数组)和p(PATH搜索)的特点
int execvpe(const char *file, char *const argv[], char *const envp[]);// 结合了v(数组)、p(PATH搜索)和e(环境变量)的特点

这个和上面6个不一样,这个是系统调用接口,上面6个是库函数调用接口。

int execve(const char *path, char *const argv[], char *const envp[]);

函数解释

  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。

  • 如果调用出错则返回-1

  • 所以exec函数只有出错的返回值而没有成功的返回值。

要执行一个程序首先就要找到这个程序,所以这里面所有的exec函数的第一个参数都是帮我们绝对如何找到这个程序的。

找到这个程序后,要告诉系统如何执行这个程序。要不要涵盖选项?涵盖哪些?

如果exec*能够实现系统程序,那么可以实现我们自己的程序吗?

可以的。


命名理解

这些函数原型看起来很容易混,但只要掌握了规律就很好记。 (lv不会同时出现)

  • l(list) : 表示参数采用列表,一个一个传参

  • v(vector) : 参数用数组

  • p(path) : 有p自动搜索环境变量PATH

  • e(env) : 表示自己维护环境变量

f3de4a863d0b715cbd337cf1b7ba08a6


3.4 多进程版 – 验证各种程序替换接口

#include <stdio.h>
#include <unistd.h>// 提供execl, getpid等函数
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>int main(){pid_t id =fork();if(id == 0){//childprintf("before: I am a process, pid:%d, ppid:%d\n",getpid(),getppid());sleep(5);execl("/usr/bin/ls","ls", "-a", "-l", NULL);printf("after: I am a process, pid:%d, ppid:%d\n",getpid(),getppid());exit(0);}//fatherpid_t ret = waitpid(id, NULL, 0);if(ret > 0){printf("wait success, father pid:%d, ret id:%d\n",getpid(), ret);}sleep(5);return 0;
}

运行结果:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ ./mycommand
before: I am a process, pid:261679, ppid:261678
total 36
drwxrwxr-x  2 ydk_108 ydk_108  4096 Jan 20 22:54 .
drwxrwxr-x 13 ydk_108 ydk_108  4096 Jan 20 22:14 ..
-rw-rw-r--  1 ydk_108 ydk_108    82 Jan 20 22:16 makefile
-rwxrwxr-x  1 ydk_108 ydk_108 17008 Jan 20 22:54 mycommand
-rw-rw-r--  1 ydk_108 ydk_108   628 Jan 20 22:54 mycommand.c
wait success, father pid:261678, ret id:261679
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ 

通过命令查看:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ while :; do ps ajx |head -1 && ps ajx |grep mycommand |grep -v grep; sleep 1;echo"----------";donePPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand261678  261679  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand261678  261679  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand261678  261679  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand261678  261679  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand261678  261679  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND261085  261678  261678  261085 pts/0     261678 S+    1001   0:00 ./mycommand
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
echo----------: command not foundPPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
echo----------: command not found
^C

程序替换有没有创建新的子进程?

没有,子进程的pid没有变。不创建新进程,只进行进程的程序代码和数据的替换结构。

补充知识:

  1. 为什么after后面的代码没有执行呢?

    因为程序替换后,afterprintf的代码已经是老程序的代码了,被ls覆盖掉了。

  2. 程序替换成功后,exit之后的代码不会执行,那么如果替换失败呢?(例如路径写错,命令不存在)

    那么程序就会继续往后走。所以exit*函数只有失败有返回值,没有成功的返回值。

  3. 我们的CPU怎么知道新程序应该进入的入口地址呢?

    Linux中形成的可执行程序是有格式的,EIF,是有可执行程序的表头的,可执行程序的入口就在表中。

  4. 实际上不只是可以调用ls命令,还可以调用自己写的C程序,python程序,shell脚本,Java程序。但是无论是我们的可执行程序还是脚本,为什么能够跨语言调用呢?

    因为所有的语言运行起来,本质上都是进程。

  5. 环境变量是什么时候给进程的呢?

    环境变量实际上也是数据。当我们创建子进程的时候,环境变量就已经被子进程继承下去了。所以程序替换中,环境变量信息不会被子进程替换。

  6. 如果我想给子进程传递环境变量,应该怎么传递呢?

    1. 新增环境变量

      直接给bash添加环境变量

      在父进程中使用putenv()添加环境变量

    2. 彻底替换环境变量

      使用execle的时候把环境变量参数换成自己的


3.5 自定义shell

touch.sh

#!/usr/bin/bashecho "hello 1"
echo "hello 1"
echo "hello 1"
echo "hello 1"
echo "hello 1"
ls -a -l

运行:bash touch.sh

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ bash touch.sh
hello 1
hello 1
hello 1
hello 1
hello 1
total 40
drwxrwxr-x  2 ydk_108 ydk_108  4096 Jan 21 00:00 .
drwxrwxr-x 13 ydk_108 ydk_108  4096 Jan 20 22:14 ..
-rw-rw-r--  1 ydk_108 ydk_108    82 Jan 20 22:16 makefile
-rwxrwxr-x  1 ydk_108 ydk_108 17008 Jan 20 22:54 mycommand
-rw-rw-r--  1 ydk_108 ydk_108   628 Jan 20 22:54 mycommand.c
-rw-rw-r--  1 ydk_108 ydk_108   101 Jan 21 00:00 touch.sh
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ 

命令行交互的shell代码:

// 包含必要的头文件
#include <stdio.h>      // 标准输入输出
#include <stdlib.h>     // 标准库函数
#include <assert.h>     // 断言
#include <string.h>     // 字符串操作
#include <unistd.h>     // UNIX标准函数
#include <sys/types.h>  // 系统数据类型
#include <sys/wait.h>   // 进程等待// 定义shell提示符的格式
#define LEFT "["        // 左边界符号
#define RIGHT "]"       // 右边界符号
#define LABLE "#"      // 提示符标签
#define DELIM " \t"    // 命令分隔符(空格和制表符)
#define LINE_SIZE 1024  // 命令行最大长度
#define ARGC_SIZE 32   // 命令参数最大个数
#define EXIT_CODE 44   // 子进程退出码// 全局变量定义
int lastcode = 0;      // 上一条命令的返回值
int quit = 0;          // 退出标志
extern char **environ; // 环境变量数组
char commandline[LINE_SIZE];  // 存储命令行
char *argv[ARGC_SIZE];        // 存储解析后的命令参数
char pwd[LINE_SIZE];          // 存储当前工作目录// 自定义环境变量存储空间
char myenv[LINE_SIZE];// 获取当前用户名
const char *getusername(){return getenv("USER");
}// 获取主机名
const char *gethostname(){return getenv("HOSTNAME");
}// 获取当前工作目录
void getpwd(){getcwd(pwd, sizeof(pwd));
}// 实现shell交互界面
void Interact(char *cline, int size){getpwd();// 打印提示符,格式为 [用户名@主机名 当前目录]#printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(), gethostname(), pwd);// 读取用户输入char *s = fgets(cline, size, stdin);assert(s);(void)s;// 去掉输入字符串末尾的换行符cline[strlen(cline)-1] = '\0';
}// 解析命令行字符串为参数数组
int splistring(char cline[], char *_argv[]){int i = 0;// 获取第一个参数(命令名)argv[i++] = strtok(cline, DELIM);// 获取后续参数while(_argv[i++] = strtok(NULL, DELIM));return i-1;  // 返回参数个数
}// 执行外部命令
void NormalExcute(char *_argv[]){pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){  // 子进程// 使用execvp执行命令execvp(_argv[0], _argv);exit(EXIT_CODE);}else{  // 父进程int status = 0;// 等待子进程结束pid_t rid = waitpid(id, &status, 0);if(rid == id){// 保存命令执行结果lastcode = WEXITSTATUS(status);}}
}// 处理内建命令
int buildCommand(char *_argv[], int _argc){// cd命令if(_argc == 2 && strcmp(_argv[0],"cd")==0){chdir(argv[1]);  // 改变当前目录getpwd();        // 更新pwdsprintf(getenv("PWD"),"%s", pwd);  // 更新PWD环境变量return 1;}// export命令:设置环境变量else if(_argc == 2 && strcmp(_argv[0],"export")==0){strcpy(myenv, _argv[1]);putenv(myenv);return 1;}// echo命令:显示文本或变量值else if(_argc == 2 && strcmp(_argv[0],"echo")==0){if(strcmp(_argv[1],"$?")==0){  // 显示上一条命令的返回值printf("%d\n",lastcode);lastcode=0;}else if(*_argv[1]=='$'){  // 显示环境变量的值char *val = getenv(_argv[1]+1);if(val) printf("%s\n",val);}else{  // 显示普通文本printf("%s\n",_argv[1]);}return 1;}// 为ls命令添加颜色支持if(strcmp(_argv[0],"ls")==0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;  // 不是内建命令
}int main(){while(!quit){//1.//2.交互问题,获取命令行Interact(commandline, sizeof(commandline));//3.子串分割的问题,解析命令行int argc = splistring(commandline, argv);if(argc == 0) continue;//4.指令的判断,判断是不是内建命令//debug//for(int i=0;argv[i];i++){//    printf("[%d]: %s\n",i,argv[i]);//}//内键命令本质上就是shell内部的一个函数。int n = buildCommand(argv, argc);//5.普通命令的执行// 如果不是内建命令,则作为外部命令执行if(!n) NormalExcute(argv);}return 0;
}

打印结果:

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ ./myshell
[ydk_108@(null) /home/ydk_108/108/lesson17]# ls -a
.  ..  makefile  mycommand  mycommand.c  myshell  myshell.c  touch.sh
[ydk_108@(null) /home/ydk_108/108/lesson17]# pwd
/home/ydk_108/108/lesson17
[ydk_108@(null) /home/ydk_108/108/lesson17]# 
Segmentation fault
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson17$ 

所以,当我们进行登陆的时候,系统就是要启动一个shell进程。

我们shell本身的环境变量是从哪里来的?

当用户登录的时候,shell会读取目录用户下的.bash_profile文件,里面保存了导入环境变量的方式。

相关文章:

【Linux】18.Linux进程控制(2)

文章目录 3. 进程程序替换3.1 单进程版 -- 看看程序替换3.2 替换原理3.3 替换函数函数解释命名理解 3.4 多进程版 -- 验证各种程序替换接口3.5 自定义shell 3. 进程程序替换 3.1 单进程版 – 看看程序替换 makefile mycommand:mycommand.cgcc -o $ $^ -stdc99 .PHONY:clean …...

reactor框架使用时,数据流请求流程

1. 我们在Flux打开时&#xff0c;可以看到 public abstract class Flux<T> implements CorePublisher<T> { 2. public interface CorePublisher<T> extends Publisher<T> {void subscribe(CoreSubscriber<? super T> subscriber); } Publish…...

读西瓜书的数学准备

1&#xff0c;高等数学&#xff1a;会求偏导数就行 2&#xff0c;线性代数&#xff1a;会矩阵运算就行 参考&#xff1a;线性代数--矩阵基本计算&#xff08;加减乘法&#xff09;_矩阵运算-CSDN博客 3&#xff0c;概率论与数理统计&#xff1a;知道啥是随机变量就行...

摄像头模块如何应用在宠物产品领域

一、宠物监控类产品 家庭宠物远程监控摄像头 1.基本功能与原理&#xff1a;这类摄像头可以通过 Wi - Fi 连接到家庭网络&#xff0c;主人可以使用手机应用程序在任何有网络连接的地方查看宠物的实时画面。摄像头模块内置有图像传感器&#xff0c;能够捕捉光线并将其转换为数字…...

c++学习第七天

创作过程中难免有不足&#xff0c;若您发现本文内容有误&#xff0c;恳请不吝赐教。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考。 一、const成员函数 //Date.h#pragma once#include<iostream> using namespace std;class Date { public:Date…...

Ubuntu 24.04 LTS 通过 docker 安装 nextcloud 搭建个人网盘

准备 Ubuntu 24.04 LTSUbuntu 空闲硬盘挂载Ubuntu 安装 Docker DesktopUbuntu 24.04 LTS 安装 tailscale [我的Ubuntu服务器折腾集](https://blog.csdn.net/jh1513/article/details/145222679。 安装 nextcloud 参考 Ubuntu24.04系统Docker安装NextcloudOnlyoffice _。 更…...

RabbitMQ1-消息队列

目录 MQ的相关概念 什么是MQ 为什么要用MQ MQ的分类 MQ的选择 RabbitMQ RabbitMQ的概念 四大核心概念 RabbitMQ的核心部分 各个名词介绍 MQ的相关概念 什么是MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&am…...

Open3D计算点云粗糙度(方法一)【2025最新版】

目录 一、Roughness二、代码实现三、结果展示博客长期更新,本文最近更新时间为:2025年1月18日。 一、Roughness 通过菜单栏的Tools > Other > Roughness找到该功能。 这个工具可以估计点云的“粗糙度”。 选择一个或几个点云,然后启动这个工具。 CloudCompare只会询问…...

算法6(力扣148)-排序链表

1、问题 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 2、采用例子 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 3、实现思路 将链表拆分成节点&#xff0c;存入数组使用sort排序&#xff0c;再用reduce重建链接 4、具…...

一文大白话讲清楚webpack基本使用——9——预加载之prefetch和preload以及webpackChunkName的使用

文章目录 一文大白话讲清楚webpack基本使用——9——预加载之prefetch和preload1. 建议按文章顺序从头看&#xff0c;一看到底&#xff0c;豁然开朗2. preload和prefetch的区别2. prefetch的使用3. preload的使用4. webpackChunkName 一文大白话讲清楚webpack基本使用——9——…...

【大数据2025】MapReduce

MapReduce 基础介绍 起源与发展&#xff1a;是 2004 年 10 月谷歌发表的 MAPREDUCE 论文的开源实现&#xff0c;最初用于大规模网页数据并行处理&#xff0c;现成为 Hadoop 核心子项目之一&#xff0c;是面向批处理的分布式计算框架。基本原理&#xff1a;分为 map 和 reduce …...

Windows图形界面(GUI)-QT-C/C++ - Qt List Widget详解与应用

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 QListWidget概述 使用场景 常见样式 QListWidget属性设置 显示方式 (Display) 交互行为 (Interaction) 高级功能 (Advanced) QListWidget常见操作 内容处理 增加项目 删除项目…...

深度学习python基础(第二节) 分支语句和循环语句

本节主要介绍分支语句和循环语句的基本语法。 注意&#xff1a;在python中的作用域以缩进为准。有语言基础的很好理解&#xff0c;了解语法格式就可以。 布尔类型和比较运算符 # True真,False假 a True print(f"布尔变量a的内容是:{a},类型是:{type(a)}") 比较运算…...

Gin 源码概览 - 路由

本文基于gin 1.1 源码解读 https://github.com/gin-gonic/gin/archive/refs/tags/v1.1.zip 1. 注册路由 我们先来看一段gin代码&#xff0c;来看看最终得到的一颗路由树长啥样 func TestGinDocExp(t *testing.T) {engine : gin.Default()engine.GET("/api/user", f…...

第6章 ThreadGroup详细讲解(Java高并发编程详解:多线程与系统设计)

1.ThreadGroup 与 Thread 在Java程序中&#xff0c; 默认情况下&#xff0c; 新的线程都会被加入到main线程所在的group中&#xff0c; main线程的group名字同线程名。如同线程存在父子关系一样&#xff0c; Thread Group同样也存在父子关系。图6-1就很好地说明了父子thread、父…...

CentOS 7乱码问题如何解决?

1.使用超级用户操作: sudo su2.修改i18n配置文件&#xff1a; vi /etc/sysconfig/i18n将文件修改或添加为以下内容&#xff1a; LANG"zh_CN.UTF8" LC_ALL"zh_CN.UTF8"保存并退出&#xff08;按Esc键&#xff0c;输入:wq&#xff0c;然后回车&#xff09…...

JavaScript语言的多线程编程

JavaScript语言的多线程编程 JavaScript是一种广泛使用的编程语言&#xff0c;主要用于网页开发。由于其单线程的特性&#xff0c;JavaScript 一直以来都有“无法进行多线程编程”的印象。尽管如此&#xff0c;随着技术的发展&#xff0c;JavaScript也逐渐引入了多线程的概念&…...

OpenSeaOtter使用手册-变更通知和持续部署

我们在OpenSeaOtter Server 0.1.1版本增加的镜像变更通知功能。通过镜像变更通知和OpenSeaOtter Agent就可以轻松获得持续部署能力。 镜像变更通知是通过push的方式下发到Agent的&#xff0c;Agent所在机器不需要外网地址。在Agent收到镜像变更通知后&#xff0c;就会调用对应的…...

(2)STM32 USB设备开发-USB虚拟串口

例程&#xff1a;STM32USBdevice: 基于STM32的USB设备例子程序 - Gitee.com 本篇为USB虚拟串口教程&#xff0c;没有知识&#xff0c;全是实操&#xff0c;按照步骤就能获得一个STM32的USB虚拟串口。本例子是在野火F103MINI开发板上验证的&#xff0c;如果代码中出现一些外设的…...

他把智能科技引入现代农业领域

江苏田倍丰农业科技有限公司&#xff08;以下简称“田倍丰”&#xff09;是一家专注于粮油种植的农业科技公司&#xff0c;为拥有300亩以上田地的大户提供全面的解决方案。田倍丰通过与当地政府合作&#xff0c;将土地承包给大户&#xff0c;并提供农资和技术&#xff0c;实现利…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

comfyui 工作流中 图生视频 如何增加视频的长度到5秒

comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗&#xff1f; 在ComfyUI中实现图生视频并延长到5秒&#xff0c;需要结合多个扩展和技巧。以下是完整解决方案&#xff1a; 核心工作流配置&#xff08;24fps下5秒120帧&#xff09; #mermaid-svg-yP…...