中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

個人網(wǎng)站 備案 廣告seo搜索引擎優(yōu)化價格

個人網(wǎng)站 備案 廣告,seo搜索引擎優(yōu)化價格,建設(shè)電子商務(wù)網(wǎng)站要素,做返利網(wǎng)站🎬 個人主頁:誰在夜里看海. 📖 個人專欄:《C系列》《Linux系列》《算法系列》 ?? 一念既出,萬山無阻 目錄 📖一、進程程序替換 1.替換的演示 ?替換與執(zhí)行流 ?程序替換≠進程替換 2.替換的原理 …

🎬?個人主頁:誰在夜里看海.

📖?個人專欄:《C++系列》《Linux系列》《算法系列》

???一念既出,萬山無阻


目錄

📖一、進程程序替換

1.替換的演示

?替換與執(zhí)行流

?程序替換≠進程替換

2.替換的原理

📚 系統(tǒng)調(diào)用exec

📚?進程控制塊 (PCB)

📚?內(nèi)存管理

3. 替換的函數(shù)

📚 execl

📚 execv

📚 execp

📚 exece

🚩本質(zhì)?

📖二、命令行解釋器shell

1.shell的本質(zhì)

2.shell的模擬實現(xiàn)

📚頭文件

📚宏定義

📚全局變量

📚獲取信息

📚交互式命令行輸入

📚字符串分割

📚內(nèi)置命令

📚普通命令

📚main函數(shù)


📖一、進程程序替換

上一篇博客我們講到了進程的誕生過程:父進程調(diào)用fork創(chuàng)建子進程,子進程執(zhí)行父進程相同的程序。但是很多時候我們希望子進程執(zhí)行另一個程序,此時就要用到exec函數(shù)調(diào)用,子進程中調(diào)用exec函數(shù)之后,該程序就會被調(diào)用的程序代替,這就是程序替換

1.替換的演示

#include<stdio.h>
#include<unistd.h>
int main()
{int a = 0;a++;execl("/usr/bin/pwd", "pwd", NULL);printf("%d\n", a++);
}

此時程序執(zhí)行結(jié)果:

我們可以看到,原先的程序執(zhí)行結(jié)果應(yīng)該是打印變量a,但是被替換成了pwd指令(指令本身也是一個可執(zhí)行程序),這就是程序替換的過程:當進程調(diào)用exec函數(shù)時,該進程的代碼和數(shù)據(jù)完全被新程序替換,從新程序的啟動例程開始執(zhí)行。

?替換與執(zhí)行流
int main()
{int a = 0;printf("Before: %d\n",a++);execl("/usr/bin/pwd", "pwd", NULL);printf("After: %d\n", a++);
}

不對呢,不是說程序替換之后原來的代碼和數(shù)據(jù)都會被替換嗎,那為什么這里還會顯示原程序的打印信息呢?下面進行分析:

?雖然進程調(diào)用exec函數(shù)后會發(fā)生程序替換,原程序的代碼和數(shù)據(jù)會被覆蓋,但在調(diào)用 exec 函數(shù)之前,執(zhí)行流還是要經(jīng)過原來的步驟的,上述代碼中,在調(diào)用execl之前,執(zhí)行流先執(zhí)行printf函數(shù)代碼,由于以“\n”結(jié)尾,輸出緩沖區(qū)的數(shù)據(jù)會被刷新到終端,所以我們能看到“Before: 0”:

修改一下代碼,結(jié)尾不加“\n”,?此時數(shù)據(jù)會被保留在輸出緩沖區(qū)當中,后面又因為發(fā)生程序替換,緩沖區(qū)的內(nèi)容被清除了,所以最終終端不會顯示"Before: 0"內(nèi)容:

int main()
{int a = 0;printf("Before: %d",a++);execl("/usr/bin/pwd", "pwd", NULL);printf("After: %d\n", a++);
}

?程序替換≠進程替換

程序替換會改變進程的執(zhí)行內(nèi)容,但它不會改變進程的進程ID,也就是說,進程還是原來的進程,程序替換并不是進程替換,且看下面示例:

先寫一個可執(zhí)行程序test2,源代碼為:

#include<stdio.h>
#include<unistd.h>int main()
{// 打印當前pid,ppidprintf("After: pid = %d, ppid = %d\n",getpid(),getppid()); 
}

另一個可執(zhí)行程序test源代碼為:

#include<stdio.h>
#include<unistd.h>int main()
{// \n結(jié)尾直接打印當前內(nèi)容printf("Before: pid = %d, ppid = %d\n",getpid(),getppid());// 程序替換成test2execl("/home/ywh/linux_gitee/test_excel/test2", "test2", NULL);
}

test執(zhí)行結(jié)果:

我們可以看到,程序替換前后都是同一個進程,結(jié)論:exec并不創(chuàng)建新進程。

2.替換的原理

📚 系統(tǒng)調(diào)用exec

exec 系列函數(shù)(如 execl, execv, execve 等)是用來將當前進程的內(nèi)存空間、程序代碼段、數(shù)據(jù)段等替換成一個新的程序。該系統(tǒng)調(diào)用不會創(chuàng)建新進程,而是直接用新程序替換當前進程的內(nèi)容。

具體來說,exec 調(diào)用會:

①:清空當前進程的代碼段、數(shù)據(jù)段、堆棧等。

②:加載并執(zhí)行新程序的代碼段、數(shù)據(jù)段、堆棧等。

③:保留當前進程的進程 ID (PID)、父進程標識符 (PPID)、文件描述符等。

📚?進程控制塊 (PCB)

操作系統(tǒng)通過 進程控制塊 (PCB) 來管理進程,每個進程都有一個獨立的 PCB,包含了進程的各種狀態(tài)信息,比如進程的 PID、父進程 ID、程序計數(shù)器、堆棧指針等。

當調(diào)用 exec 時,進程的 PCB 中的狀態(tài)信息并沒有被改變,操作系統(tǒng)只會根據(jù) exec 調(diào)用的參數(shù)加載新的程序內(nèi)容(代碼段、數(shù)據(jù)段等),并且更新程序計數(shù)器和堆棧指針等信息。

📚?內(nèi)存管理

操作系統(tǒng)中的內(nèi)存管理模塊負責為進程分配內(nèi)存。當進程調(diào)用 exec 時,操作系統(tǒng)會:

①:釋放原進程的內(nèi)存(代碼段、數(shù)據(jù)段、堆棧)。

②:加載新程序的內(nèi)存:從磁盤(例如 ELF 文件或其他可執(zhí)行文件)中加載新的程序到內(nèi)存,包括新的代碼段、數(shù)據(jù)段等。

③:更新堆棧和堆的布局,準備新程序的運行環(huán)境。

3. 替換的函數(shù)

其實有六種以exec開頭的函數(shù),統(tǒng)稱exec函數(shù):

 #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[]);

為了便于理解,我們可以把exec后面出現(xiàn)的?l、p、e、v?看作exec的四個選項,下面我們依次介紹這些選項:

📚 execl

l(list) : 參數(shù)采用列表?

path:表示要執(zhí)行的程序路徑;

arg:表示程序本身的參數(shù),第一個是程序本身的名稱,后續(xù)為程序的參數(shù)(傳遞系統(tǒng)指令時,參數(shù)就是指令的選項),必須以NULL結(jié)尾。

示例:

execl("/bin/ls", "ls", "-l", (char *)NULL);
📚 execv

v(vector) : 參數(shù)用數(shù)組

path:表示要執(zhí)行的程序路徑;

argv:參數(shù)列表,程序的參數(shù)以數(shù)組的形式傳遞,數(shù)組內(nèi)部也必須以NULL結(jié)尾。

示例:

execv("/bin/ls", (char *[]){"ls", "-l", NULL});
📚 execp

p(path) : 自動搜索環(huán)境變量PATH

它可以通過環(huán)境變量 PATH 來查找可執(zhí)行文件,而不需要提供絕對路徑。

示例:

execlp("ls", "ls", "-l", (char *)NULL);
📚 exece

e(env) : 表示自己維護環(huán)境變量?

execle 允許顯式地傳遞一個 環(huán)境變量數(shù)組,而不是繼承當前進程的環(huán)境變量。通過 execle,你可以自定義新進程的環(huán)境變量。

示例:

char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
execle("ps", "ps", "-ef", NULL, envp);
🚩本質(zhì)?

事實上,只有execve才是真正的系統(tǒng)調(diào)用,而其他四個函數(shù)最后都會調(diào)用execve:

📖二、命令行解釋器shell

我們在linux學習過程中離不開shell,shell是命令行解釋工具,是用戶與內(nèi)核之間的工具,提供了一個接口,通過它,我們可以執(zhí)行命令、啟動程序等與操作系統(tǒng)進行交互。shell解析用戶輸入的命令,返回執(zhí)行結(jié)果。

?shell的本質(zhì)是什么呢?

1.shell的本質(zhì)

?shell本質(zhì)其實是一個進程

當我們啟動一個終端或打開一個命令行窗口的時候,相當于啟動了一個shell進程(也叫bash進程),這個進程會等待用戶輸入的命令,并將命令通過系統(tǒng)調(diào)用傳遞給內(nèi)核,內(nèi)核執(zhí)行相應(yīng)的操作后,返回給shell。

shell的工作原理就是循環(huán)以下操作

1??獲取命令行 --> 2??解析命令行 --> 3??fork創(chuàng)建子進程?

--> 4??execve替換子進程 --> 5??wait等待子進程退出 ->1??

根據(jù)這些思路,我們可以模擬實現(xiàn)一個shell:

2.shell的模擬實現(xiàn)

實現(xiàn)一個簡化版的shell,需要執(zhí)行以下功能:

① 獲取當前工作目錄、用戶名、主機名。

② 解析用戶輸入的命令行并執(zhí)行命令。

③ 內(nèi)置支持一些常見命令,如cd、echo、export等。

④ 創(chuàng)建子進程來執(zhí)行普通命令,并支持基本的命令分割和管道處理。

📚頭文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

這些頭文件提供了標準輸入輸出、字符串處理、系統(tǒng)調(diào)用等功能。unistd包含與進程相關(guān)的函數(shù)(如fork,exit)

📚宏定義
#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44

LEFT、RIGHT、LABLE:用于命令行提示符的格式化;

DELIM:用于命令行字符串的分隔符;

LINE_SIZE、ARGC_SIZE:定義了命令行和參數(shù)的緩沖區(qū)大小;

EXIT_CODE:用于子進程異常退出的返回值。

📚全局變量
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];

lastcode:保存上一個命令的退出碼;

quit:用于控制shell是否退出;

commandline:存儲用戶輸入的命令行字符串;

argv:存儲解析后的命令和參數(shù);

pwd:保存當前工作目錄;

myenv:存儲自定義的環(huán)境變量。

📚獲取信息
const char *getusername() {return getenv("USER");
}const char *gethostname() {return getenv("HOSTNAME");
}void getpwd() {getcwd(pwd, sizeof(pwd));
}

getusername:獲取用戶名

gethostname:獲取主機名

getpwd:獲取當前工作目錄

📚交互式命令行輸入
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';
}

interact函數(shù)顯示格式化的提示符,并等待用戶輸入命令。輸入命令存儲在cline中;輸入的命令符末行換行符替換成終止符 '\0'。

📚字符串分割
int splitstring(char cline[], char *_argv[]) {int i = 0;argv[i++] = strtok(cline, DELIM);while(_argv[i++] = strtok(NULL, DELIM));return i - 1;
}

splitstring函數(shù)使用strtok將輸入的命令行字符串按空格和制表符分割成多個命令或參數(shù),存儲在指針數(shù)組argv中。

📚內(nèi)置命令
int buildCommand(char *_argv[], int _argc) {if(_argc == 2 && strcmp(_argv[0], "cd") == 0) {chdir(argv[1]);getpwd();sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0) {strcpy(myenv, _argv[1]);putenv(myenv);return 1;}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;}if(strcmp(_argv[0], "ls") == 0) {_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}

提供了幾個內(nèi)置命令:

cd:改變當前目錄

export:設(shè)置一個新的環(huán)境變量

enho:打印變量值或退出碼

📚普通命令

隊友普通命令的執(zhí)行,需要調(diào)用exec程序替換成目標命令的程序:

void NormalExcute(char *_argv[]) {pid_t id = fork();if(id < 0) {perror("fork");return;}else if(id == 0) {execvp(_argv[0], _argv);exit(EXIT_CODE);}else {int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid == id) {lastcode = WEXITSTATUS(status);}}
}

NormalExcute使用fork創(chuàng)建子進程,子進程調(diào)用execvp,替換當前程序,父進程等待子進程結(jié)束。

📚main函數(shù)
int main() {while(!quit) {interact(commandline, sizeof(commandline));int argc = splitstring(commandline, argv);if(argc == 0) continue;int n = buildCommand(argv, argc);if(!n) NormalExcute(argv);}return 0;
}

main函數(shù)進入循環(huán),不斷接收用戶輸入的命令并解析執(zhí)行。

如果命令是內(nèi)置命令,則在當前進程中執(zhí)行;如果是普通命令,通過程序替換在子進程中執(zhí)行。


以上就是【劇幕中的靈魂更迭:探索Shell下的程序替換】的全部內(nèi)容,歡迎指正~??

碼文不易,還請多多關(guān)注支持,這是我持續(xù)創(chuàng)作的最大動力!?

http://www.risenshineclean.com/news/33323.html

相關(guān)文章:

  • 72搭建網(wǎng)站網(wǎng)頁代引流推廣公司
  • 想開個網(wǎng)站賣衣服的怎么做常州seo收費
  • 有交做拼多多網(wǎng)站的嗎產(chǎn)品推廣平臺有哪些
  • 自己做網(wǎng)站賣什么海南樂秀同城群軟件下載
  • 做網(wǎng)站公司南京關(guān)鍵詞免費網(wǎng)站
  • c 做網(wǎng)站設(shè)計關(guān)鍵詞排名提高方法
  • pageadmin如何做網(wǎng)站數(shù)據(jù)分析培訓班
  • 代還信用卡網(wǎng)站建設(shè)國內(nèi)最新十大新聞
  • .net mvc做網(wǎng)站一鍵優(yōu)化清理
  • 單縣網(wǎng)站定制網(wǎng)絡(luò)營銷策劃的主要特點
  • 國外網(wǎng)站 服務(wù)器青島seo排名公司
  • 網(wǎng)頁即時聊天seo推廣怎么樣
  • 用動物做網(wǎng)站名稱可以投放廣告的網(wǎng)站
  • 沒有備案的網(wǎng)站可以做淘寶客seo網(wǎng)絡(luò)推廣培訓班
  • 校園論壇網(wǎng)站怎么做谷歌收錄提交入口
  • 長沙岳麓區(qū)做網(wǎng)站seo內(nèi)容優(yōu)化是什么
  • 怎么做網(wǎng)站首頁全媒體廣告代理
  • 去國外做移動支付網(wǎng)站嗎廣告投放網(wǎng)站
  • 四川網(wǎng)站建設(shè)一站式服務(wù)商互聯(lián)網(wǎng)公司網(wǎng)站模板
  • 企業(yè)oa系統(tǒng)免費優(yōu)化網(wǎng)站建設(shè)seo
  • 淘寶做個網(wǎng)站多少錢seo概念
  • 一級a做爰片免費無碼網(wǎng)站網(wǎng)絡(luò)流量分析工具
  • php網(wǎng)站開發(fā)百度云產(chǎn)品推廣計劃方案
  • 網(wǎng)站對比app還有優(yōu)勢嗎2023第三波疫情已經(jīng)到來了
  • 網(wǎng)站空間多久續(xù)一次費seo優(yōu)化團隊
  • 鎮(zhèn)江外貿(mào)網(wǎng)站建設(shè)站外推廣渠道有哪些
  • Axure只是做網(wǎng)站嗎怎么注冊一個自己的網(wǎng)址
  • 湛江自做網(wǎng)站杭州谷歌推廣
  • 河南科興建設(shè)有限公司網(wǎng)站網(wǎng)站推廣公司黃頁
  • 石家莊專業(yè)商城網(wǎng)站制作百度如何優(yōu)化