欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux信號(hào)機(jī)制之信號(hào)的保存與處理技巧分享

 更新時(shí)間:2024年10月15日 08:50:51   作者:Eternity._  
本文旨在為廣大Linux學(xué)習(xí)者提供一份詳盡而實(shí)用的指南,幫助他們深入理解Linux中的信號(hào)機(jī)制,掌握信號(hào)的保存與處理技巧,我們將從信號(hào)的基本概念出發(fā),逐步深入到信號(hào)的捕獲、保存、處理以及恢復(fù)等各個(gè)環(huán)節(jié),通過(guò)生動(dòng)的實(shí)例和詳細(xì)的解釋,讓讀者能夠輕松掌握

前言:在Linux操作系統(tǒng)的廣闊天地中,信號(hào)機(jī)制無(wú)疑是一個(gè)充滿挑戰(zhàn)與機(jī)遇的領(lǐng)域。信號(hào),作為進(jìn)程間通信的一種重要方式,不僅承載著豐富的信息,還扮演著進(jìn)程控制與管理的重要角色。然而,對(duì)于許多初學(xué)者而言,信號(hào)的保存與處理往往是一個(gè)難以逾越的障礙

讓我們一同踏上這段充滿探索與發(fā)現(xiàn)的旅程,共同揭開(kāi)Linux信號(hào)機(jī)制的神秘面紗吧!

1. 信號(hào)的保存

信號(hào)其他相關(guān)常見(jiàn)概念

  • 實(shí)際執(zhí)行信號(hào)的處理動(dòng)作稱為信號(hào)遞達(dá)(Delivery)
  • 信號(hào)從產(chǎn)生到遞達(dá)之間的狀態(tài),稱為信號(hào)未決(Pending)
  • 進(jìn)程可以選擇阻塞 (Block )某個(gè)信號(hào)
  • 被阻塞的信號(hào)產(chǎn)生時(shí)將保持在未決狀態(tài),直到進(jìn)程解除對(duì)此信號(hào)的阻塞,才執(zhí)行遞達(dá)的動(dòng)作
  • 注意:阻塞和忽略是不同的,只要信號(hào)被阻塞就不會(huì)遞達(dá),而忽略是在遞達(dá)之后可選的一種處理動(dòng)作

在內(nèi)核中的表示

在Linux內(nèi)核中,信號(hào)的保存主要依賴于三種數(shù)據(jù)結(jié)構(gòu):pending表、block表和handler表

pending表:

  • pending表是一張位圖(bitmap),用于記錄當(dāng)前進(jìn)程是否收到了信號(hào),以及收到了哪些信號(hào)
  • 當(dāng)進(jìn)程接收到一個(gè)信號(hào)時(shí),對(duì)應(yīng)的信號(hào)位圖上的比特位就會(huì)由0置1,表示該信號(hào)處于未決(Pending)狀態(tài)

block表:

  • block表也是一張位圖,用于記錄特定信號(hào)是否被屏蔽(阻塞)
  • 比特位的內(nèi)容為0表示不屏蔽,為1表示屏蔽。屏蔽的信號(hào)在解除屏蔽之前不會(huì)被操作系統(tǒng)處理

handler表:

  • handler表是一個(gè)函數(shù)指針數(shù)組,用于保存每個(gè)信號(hào)對(duì)應(yīng)的處理方法
  • 這些處理方法可以是默認(rèn)的,或者忽略的,當(dāng)然也可以是用戶自定義的。當(dāng)信號(hào)被遞達(dá)時(shí),操作系統(tǒng)會(huì)根據(jù)handler表找到對(duì)應(yīng)的處理方法并執(zhí)行

在這里插入圖片描述

舉個(gè)例子:上圖SIGINT信號(hào)產(chǎn)生過(guò),但正在被阻塞,所以暫時(shí)不能遞達(dá)。雖然它的處理動(dòng)作是忽略,但在沒(méi)有解除阻塞之前不能忽略這個(gè)信號(hào),因?yàn)檫M(jìn)程仍有機(jī)會(huì)改變處理動(dòng)作之后再解除阻塞

sigset_t

sigset_t是一個(gè)在Unix和Linux系統(tǒng)中用于表示信號(hào)集的數(shù)據(jù)類型。信號(hào)集本質(zhì)上是一個(gè)信號(hào)的集合,用于指定多個(gè)信號(hào),通過(guò)使用sigset_t,可以輕松地指定一組信號(hào),并在諸如信號(hào)阻塞、信號(hào)等待等操作中使用這組信號(hào)

sigset_t信號(hào)集操作函數(shù):

  • sigemptyset():初始化信號(hào)集,將其設(shè)置為空集
  • sigfillset():初始化信號(hào)集,將其設(shè)置為包含所有信號(hào)的集合
  • sigaddset():向信號(hào)集中添加一個(gè)信號(hào)
  • sigdelset():從信號(hào)集中刪除一個(gè)信號(hào)
  • sigismember():檢查一個(gè)信號(hào)是否屬于某個(gè)信號(hào)集

2. 信號(hào)集操作函數(shù)

信號(hào)集操作函數(shù)用于處理與信號(hào)集(sigset_t類型)相關(guān)的操作。這些函數(shù)允許用戶初始化信號(hào)集、添加或刪除信號(hào)、檢查信號(hào)是否存在于信號(hào)集中,以及修改進(jìn)程的信號(hào)屏蔽字

sigprocmask()函數(shù):

讀取或更改進(jìn)程的信號(hào)屏蔽字(阻塞信號(hào)集)

在這里插入圖片描述

返回值:若成功則為0,若出錯(cuò)則為-1

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

如果oset是非空指針,則讀取進(jìn)程的當(dāng)前信號(hào)屏蔽字通過(guò)oset參數(shù)傳出。如果set是非空指針,則 更改進(jìn)程的信號(hào)屏蔽字,參數(shù)how指示如何更改。如果oset和set都是非空指針,則先將原來(lái)的信號(hào) 屏蔽字備份到oset里,然后根據(jù)set和how參數(shù)更改信號(hào)屏蔽字。假設(shè)當(dāng)前的信號(hào)屏蔽字為mask,下表說(shuō)明了how參數(shù)的可選值

在這里插入圖片描述

代碼示例:

void headler(int signo)
{
    cout << "headler: " << signo << endl;
    // exit(0);
}

int main()
{
    cout << "pid: " << getpid() << endl;
    signal(2, headler);

    sigset_t block, oblock;
	
	// 初始化
    sigemptyset(&block);
    sigemptyset(&oblock);

    sigaddset(&block, 2); // 設(shè)置對(duì)2號(hào)信號(hào)的屏蔽

    sigprocmask(SIG_BLOCK, &block, &oblock);

    while(1)
    {
        sleep(1);
    }

    return 0;
}

在這里插入圖片描述

那我們到底能不能屏蔽所有普通信號(hào)呢?我們來(lái)測(cè)試一下

修改代碼:

for(int signo = 1; signo <= 31; signo++) sigaddset(&block, signo);

在這里插入圖片描述

在這里插入圖片描述

我們發(fā)現(xiàn)9號(hào)信號(hào),19號(hào)信號(hào)是不會(huì)被屏蔽的

注意:如果調(diào)用sigprocmask解除了對(duì)當(dāng)前若干個(gè)未決信號(hào)的阻塞,則在sigprocmask返回前,至少將其中一個(gè)信號(hào)遞達(dá)

sigpending()函數(shù):

讀取當(dāng)前進(jìn)程的未決信號(hào)集,通過(guò)set參數(shù)傳出

在這里插入圖片描述

返回值:調(diào)用成功則返回0,出錯(cuò)則返回-1

int sigpending(sigset_t *set);

代碼示例:

void PrintPending(const sigset_t &pending)
{
    for(int signo = 32; signo > 0; signo--)
    {
        if(sigismember(&pending, signo))
        {
            cout << "1";
        }
        else{
            cout << "0";
        }
    }
    cout << endl;
}

int main()
{
	cout << "pid: " << getpid() << endl;
	
    // 屏蔽2號(hào)信號(hào)
    sigset_t set, oset;

    sigemptyset(&set);
    sigemptyset(&oset);

    sigaddset(&set, 2);
    sigprocmask(SIG_BLOCK, &set, &oset);
	
	int cnt = 0;    
    // 讓進(jìn)程不斷獲取當(dāng)前進(jìn)程的pending
    sigset_t pending;
    while(1)
    {
        sigpending(&pending);
        PrintPending(pending);
        sleep(1);
		
		// 對(duì)2好信號(hào)進(jìn)行解除屏蔽
		cnt++;
		if(cnt == 16)
		{
			cout << "對(duì)2號(hào)信號(hào)進(jìn)行解除屏蔽,準(zhǔn)備遞達(dá)" << endl;
			sigprocmask(SIG_SETMASK, &oset, nullptr);
		}
    }
    return 0;
}

在這里插入圖片描述

當(dāng)我們對(duì)信號(hào)進(jìn)行處理的時(shí)候,會(huì)先將pending位圖中的1 -> 0,然后再去調(diào)用信號(hào)捕捉方法

3. 信號(hào)的處理

進(jìn)程從內(nèi)核態(tài)返回到用戶態(tài)的時(shí)候(包含身份的變化),進(jìn)行信號(hào)的檢測(cè)和信號(hào)的處理

  • 用戶態(tài)是一種受控的狀態(tài),能夠訪問(wèn)的資源是有限的(只能訪問(wèn)自己的[ 0 - 3GB] )
  • 內(nèi)核態(tài)是一種操作系統(tǒng)的工作狀態(tài),能夠訪問(wèn)大部分系統(tǒng)資源(可以讓用戶以O(shè)S的身份訪問(wèn)[ 3 - 4GB])

調(diào)用系統(tǒng)調(diào)用接口就是在進(jìn)程地址空間中進(jìn)行的!

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

sigaction

sigaction是一個(gè)POSIX標(biāo)準(zhǔn)的系統(tǒng)調(diào)用,用于更改和檢查信號(hào)的處理方式。與傳統(tǒng)的signal函數(shù)相比,sigaction提供了更多的控制選項(xiàng)和更可靠的信號(hào)處理方式

在這里插入圖片描述

int sigaction(int signo, const struct sigaction *act, struct sigaction *oldact);
  • signum:信號(hào)編號(hào),指定要設(shè)置的信號(hào)
  • act:指向sigaction結(jié)構(gòu)的指針,在sigaction的實(shí)例中指定了對(duì)特定信號(hào)的處理。如果為NULL,則進(jìn)程會(huì)以缺省方式對(duì)信號(hào)處理
  • oldact:指向的對(duì)象用來(lái)保存原來(lái)對(duì)相應(yīng)信號(hào)的處理,如果為NULL,則不保存

act和oldact指向sigaction結(jié)構(gòu)體

在這里插入圖片描述

代碼示例:

void Print(const sigset_t &pending);

void handler(int signo)
{
    cout << "get a signo: " << signo << endl;

    while(1)
    {
        sigset_t pending;
        sigpending(&pending);
        Print(pending);
        
        sleep(1);
    }
}

void Print(const sigset_t &pending)
{
    for(int signo = 31; signo > 0; signo--)
    {
        if(sigismember(&pending, signo))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

int main()
{
    cout << "pid: " << getpid() << endl;

    struct sigaction act, oact;
    act.sa_handler = handler;

    // 增加對(duì)3號(hào)信息的屏蔽
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, 3);

    // 對(duì)2信號(hào)進(jìn)行屏蔽
    sigaction(2, &act, &oact); 

    while(1) sleep(1);

    return 0;
}

在這里插入圖片描述

當(dāng)某個(gè)信號(hào)的處理函數(shù)被調(diào)用時(shí),內(nèi)核自動(dòng)將當(dāng)前信號(hào)加入進(jìn)程的信號(hào)屏蔽字,當(dāng)信號(hào)處理函數(shù)返回時(shí)自動(dòng)恢復(fù)原來(lái)的信號(hào)屏蔽字,這樣就保證了在處理某個(gè)信號(hào)時(shí),如果這種信號(hào)再次產(chǎn)生,那么 它會(huì)被阻塞到當(dāng)前處理結(jié)束為止,如果在調(diào)用信號(hào)處理函數(shù)時(shí),除了當(dāng)前信號(hào)被自動(dòng)屏蔽之外,還希望自動(dòng)屏蔽另外一些信號(hào),則用sa_mask字段說(shuō)明這些需要額外屏蔽的信號(hào),當(dāng)信號(hào)處理函數(shù)返回時(shí)自動(dòng)恢復(fù)原來(lái)的信號(hào)屏蔽字

多個(gè)信號(hào)情況:

代碼示例:

void Print(const sigset_t &pending);

void handler(int signo)
{
    cout << "get a signo: " << signo << endl;
    sleep(1);
}

void Print(const sigset_t &pending)
{
    for(int signo = 31; signo > 0; signo--)
    {
        if(sigismember(&pending, signo))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

int main()
{
    signal(2, handler);
    signal(3, handler);
    signal(4, handler);
    signal(5, handler);

    sigset_t mask, omask;
    sigemptyset(&mask);
    sigemptyset(&omask);

    sigaddset(&mask, 2);
    sigaddset(&mask, 3);
    sigaddset(&mask, 4);
    sigaddset(&mask, 5);

    sigprocmask(SIG_SETMASK, &mask, &omask);

    cout << "pid: " << getpid() << endl;

    int cnt = 20;
    while(1) 
    {
        sigset_t pending;
        sigpending(&pending);
        Print(pending);

        cnt--;
        sleep(1);
        if(cnt == 0)
        {
            sigprocmask(SIG_SETMASK, &omask, nullptr);
            cout << "cancel 2,3,4,5 block" << endl;
        }
    }

    return 0;
}

在這里插入圖片描述

由實(shí)驗(yàn)結(jié)果來(lái)看,我們系統(tǒng)是等所有的信號(hào)處理完全了,統(tǒng)一再進(jìn)行返回的,并且他并不是按照順序來(lái)處理信號(hào)的

在這里插入圖片描述

4. 可重入函數(shù)

可重入函數(shù)是指可以被多個(gè)任務(wù)(如線程、進(jìn)程)同時(shí)調(diào)用,并且能保證每個(gè)任務(wù)調(diào)用該函數(shù)時(shí)都能得到正確結(jié)果的函數(shù)。換句話說(shuō),這種函數(shù)在執(zhí)行的任何時(shí)刻都可以被中斷,然后在中斷點(diǎn)恢復(fù)執(zhí)行而不會(huì)導(dǎo)致錯(cuò)誤

在這里插入圖片描述

  • main函數(shù)調(diào)用 insert函數(shù)向一個(gè)鏈表head中插入節(jié)點(diǎn)node1,插入操作分為兩步,剛做完第一步的 時(shí)候,因?yàn)橛布袛嗍惯M(jìn)程切換到內(nèi)核,再次回用戶態(tài)之前檢查到有信號(hào)待處理,于是切換 到sighandler函數(shù),sighandler也調(diào)用insert函數(shù)向同一個(gè)鏈表head中插入節(jié)點(diǎn)node2,插入操作的 兩步都做完之后從sighandler返回內(nèi)核態(tài),再次回到用戶態(tài)就從main函數(shù)調(diào)用的insert函數(shù)中繼續(xù) 往下執(zhí)行,先前做第一步之后被打斷,現(xiàn)在繼續(xù)做完第二步。結(jié)果是,main函數(shù)和sighandler先后 向鏈表中插入兩個(gè)節(jié)點(diǎn),而最后只有一個(gè)節(jié)點(diǎn)真正插入鏈表中
  • insert函數(shù)被不同的控制流程調(diào)用,有可能在第一次調(diào)用還沒(méi)返回時(shí)就再次進(jìn)入該函數(shù),這稱為重入,insert函數(shù)訪問(wèn)一個(gè)全局鏈表,有可能因?yàn)橹厝攵斐慑e(cuò)亂,像這樣的函數(shù)稱為 不可重入函數(shù),反之,如果一個(gè)函數(shù)只訪問(wèn)自己的局部變量或參數(shù),則稱為可重入(Reentrant) 函數(shù)

不可重入函數(shù)(符合以下任一條件):

  • 調(diào)用了malloc或free,因?yàn)閙alloc也是用全局鏈表來(lái)管理堆的
  • 調(diào)用了標(biāo)準(zhǔn)I/O庫(kù)函數(shù),標(biāo)準(zhǔn)I/O庫(kù)的很多實(shí)現(xiàn)都以不可重入的方式使用全局?jǐn)?shù)據(jù)結(jié)構(gòu)

5. volatile

volatile是一個(gè)類型修飾符,用于告訴虛擬機(jī)該變量是極有可能多變的,從而免于一些優(yōu)化措施,確保變量的正確性和線程間的通信。它主要用于多線程環(huán)境下的變量共享,確保變量的可見(jiàn)性和有序性

代碼示例:

#include <iostream>
#include <signal.h>
#include <unistd.h>

using namespace std;

int flag = 0;

void headler(int signo)
{
    cout << "signo: " << signo << endl;
    flag = 1;
    cout << "change flag to: " << flag << endl;
}

int main()
{
    signal(2, headler);

    cout << "pid: " << getpid() << endl;
    while(!flag);
    cout << "qiut normal!" << endl;
    return 0;
}

標(biāo)準(zhǔn)情況下,鍵入 CTRL-C ,2號(hào)信號(hào)被捕捉,執(zhí)行自定義動(dòng)作,修改 flag=1 , while 條件不滿足,退出循環(huán),進(jìn)程退出

在這里插入圖片描述

優(yōu)化情況下(-O2)(不是數(shù)字0),鍵入 CTRL-C ,2號(hào)信號(hào)被捕捉,執(zhí)行自定義動(dòng)作,修改 flag=1 ,但是 while 條件依舊滿足,進(jìn)程繼續(xù)運(yùn)行

在這里插入圖片描述

在這里插入圖片描述

所以要想不讓編譯器優(yōu)化,我們需要加上volatile

volatile int flag = 0;

在這里插入圖片描述

6. 總結(jié)

SIGCHLD信號(hào)(了解)

SIGCHLD信號(hào)在子進(jìn)程狀態(tài)改變時(shí)發(fā)送給其父進(jìn)程。子進(jìn)程的狀態(tài)改變包括以下幾種情況:

  • 子進(jìn)程終止,無(wú)論是正常終止還是異常終止(如有core dump或無(wú)core dump)
  • 子進(jìn)程停止,例如接收到SIGSTOP信號(hào)
  • 停止的子進(jìn)程被SIGCONT信號(hào)喚醒并繼續(xù)執(zhí)行

代碼示例:

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/wait.h> 

using namespace std;

void handle(int signo) {  
    int status;  
    pid_t pid;  
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {  
        if (WIFEXITED(status)) {  
            printf("Child %d exited with status %d\n", pid, WEXITSTATUS(status));  
        } else if (WIFSIGNALED(status)) {  
            printf("Child %d killed by signal %d\n", pid, WTERMSIG(status));  
        }  
    }  
}  
  
int main() {  
    pid_t pid;  
    struct sigaction act;  
  
    // 設(shè)置SIGCHLD信號(hào)的處理函數(shù)  
    act.sa_handler = handle;  
    sigemptyset(&act.sa_mask);  
    act.sa_flags = 0;  
    sigaction(SIGCHLD, &act, NULL);  
  
    // 創(chuàng)建子進(jìn)程  
    pid = fork();  
    if (pid < 0) 
    {  
        perror("fork");  
        exit(1);  
    } 
    else if (pid == 0)
     {  
        // 子進(jìn)程代碼  
        printf("Child process (PID: %d) is running\n", getpid());  
        sleep(5); // 模擬子進(jìn)程工作  
        exit(0);  // 子進(jìn)程正常退出  
    } 
    else 
    {  
        // 父進(jìn)程代碼  
        printf("Parent process (PID: %d) is running\n", getpid());  
        // 父進(jìn)程可以繼續(xù)執(zhí)行其他任務(wù),等待SIGCHLD信號(hào)來(lái)回收子進(jìn)程  
        while (1) {  
            sleep(10); // 模擬父進(jìn)程工作  
            printf("Parent process is still running\n");  
        }  
    }  
  
    return 0;  
}

父進(jìn)程設(shè)置了SIGCHLD信號(hào)的處理函數(shù)handle_sigchld,該函數(shù)會(huì)在子進(jìn)程狀態(tài)改變時(shí)被調(diào)用。在處理函數(shù)中,父進(jìn)程使用waitpid()函數(shù)來(lái)回收子進(jìn)程的資源

在這里插入圖片描述

隨著我們對(duì)Linux中信號(hào)保存與處理機(jī)制的深入探討,我們不難發(fā)現(xiàn),信號(hào)不僅是進(jìn)程間通信的一種重要手段,更是Linux操作系統(tǒng)內(nèi)核提供的一種強(qiáng)大而靈活的控制機(jī)制。通過(guò)信號(hào)的捕獲、保存、處理以及恢復(fù),我們可以實(shí)現(xiàn)對(duì)進(jìn)程行為的精確控制,從而滿足各種復(fù)雜的系統(tǒng)需求

以上就是Linux信號(hào)機(jī)制之信號(hào)的保存與處理技巧分享的詳細(xì)內(nèi)容,更多關(guān)于Linux信號(hào)機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 淺談linux線程切換問(wèn)題

    淺談linux線程切換問(wèn)題

    下面小編就為大家?guī)?lái)一篇淺談linux線程切換問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • Windows10安裝linux子系統(tǒng)的兩種方式(圖文詳解)

    Windows10安裝linux子系統(tǒng)的兩種方式(圖文詳解)

    這篇文章主要介紹了Windows10安裝linux子系統(tǒng)的兩種方式,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Linux下如何查看隱藏文件命令

    Linux下如何查看隱藏文件命令

    這篇文章主要介紹了Linux下如何查看隱藏文件命令問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 詳解apache配置域名的坑

    詳解apache配置域名的坑

    這篇文章主要介紹了詳解apache配置域名的坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Linux系統(tǒng)下Nginx支持ipv6配置的方法

    Linux系統(tǒng)下Nginx支持ipv6配置的方法

    這篇文章主要介紹了Linux系統(tǒng)下Nginx支持ipv6的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • linux壓縮解壓命令使用方式(無(wú)廢話版)

    linux壓縮解壓命令使用方式(無(wú)廢話版)

    本文介紹了gzip、bzip2、tar和zip四種常用的文件壓縮和打包工具的使用方法,包括它們的功能、壓縮比率、使用場(chǎng)景以及基本命令示例
    2024-11-11
  • Centos7服務(wù)器下啟動(dòng)jar包項(xiàng)目的最佳方法

    Centos7服務(wù)器下啟動(dòng)jar包項(xiàng)目的最佳方法

    這篇文章主要給大家分享介紹了關(guān)于Centos7服務(wù)器下啟動(dòng)jar包項(xiàng)目的最佳方法,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Linux下安裝PHP curl擴(kuò)展的方法詳解

    Linux下安裝PHP curl擴(kuò)展的方法詳解

    這篇文章主要介紹了Linux下安裝PHP curl擴(kuò)展的方法,簡(jiǎn)單分析了Linux環(huán)境安裝php的curl擴(kuò)展具體步驟、相關(guān)命令與注意事項(xiàng),需要的朋友可以參考下
    2019-07-07
  • PHP程序員玩轉(zhuǎn)Linux系列 Linux和Windows安裝nginx

    PHP程序員玩轉(zhuǎn)Linux系列 Linux和Windows安裝nginx

    這篇文章主要為大家詳細(xì)介紹了PHP程序員玩轉(zhuǎn)Linux系列文章,Linux和Windows安裝nginx教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • winxp apache用php建本地虛擬主機(jī)的方法

    winxp apache用php建本地虛擬主機(jī)的方法

    windows xp用php建本地虛擬主機(jī)的方法(注:以下目錄是筆者系統(tǒng)目錄)
    2009-07-07

最新評(píng)論