日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

多实例多进程网络编程PHP,php socket网络编程基础知识(四):多进程

發(fā)布時(shí)間:2025/3/15 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多实例多进程网络编程PHP,php socket网络编程基础知识(四):多进程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

標(biāo)簽:status???傳遞???windows???返回???修改???隊(duì)列???_for???響應(yīng)???關(guān)聯(lián)

說明

php在web編程時(shí)是不需要考慮多進(jìn)程的,但整個(gè)php流程是涉及到多進(jìn)程的,只不過nginx、php-fpm幫我們處理好了,我們配置他們參數(shù)時(shí)就需要設(shè)置進(jìn)程個(gè)數(shù)相關(guān)參數(shù)

php在多進(jìn)程涉及到的是PCNTL擴(kuò)展和POSIX擴(kuò)展,這兩個(gè)擴(kuò)展交叉涉及到進(jìn)程和信號相關(guān),他們只支持Unix平臺,windows平臺不支持,而且只支持cli模式下運(yùn)行。

php也提供了其它函數(shù)來處理多進(jìn)程的場景,例如exec相關(guān)的函數(shù),所以并不是涉及到多進(jìn)程都需要上方擴(kuò)展,推薦symfony/process,對php此類相關(guān)函數(shù)進(jìn)行的封裝和兼容處理,同時(shí)支持linux和windows,非常好用的多進(jìn)程庫,一般的中小項(xiàng)目完全滿足需求。

我們只從上方擴(kuò)展中找進(jìn)程相關(guān)的函數(shù)來總結(jié),信號相關(guān)的在下節(jié)中總結(jié)

概念

這里涉及到一些linux系統(tǒng)相關(guān)的的概念,可能需要先做了解

僵尸進(jìn)程和孤兒進(jìn)程,簡單來說就是子進(jìn)程結(jié)束而父進(jìn)程沒有回收善后處理則產(chǎn)生僵尸進(jìn)程,而父進(jìn)程提前結(jié)束而子進(jìn)程還存在則產(chǎn)生孤兒進(jìn)程,可參考PHP多進(jìn)程初探 --- 孤兒和僵尸,

用戶(uid)和用戶組(gid),這個(gè)大家應(yīng)該都清楚,創(chuàng)建linux用戶、指定nginx等執(zhí)行用戶和用戶組、設(shè)置文件權(quán)限都會用到,還有有效用戶(euid)和有效組(egid),感興趣的可以去自行搜索。

進(jìn)程(pid,英文:process ID)、父進(jìn)程(ppid)、進(jìn)程組(pgid)、會話組(sid),例如我們從終端xshell登陸,就會產(chǎn)生一個(gè)會話組,然后我們執(zhí)行命令,會在會話組下產(chǎn)生進(jìn)程組,而進(jìn)程組中就包含各種進(jìn)程??梢詤⒖紡倪M(jìn)程組、會話、終端的概念深入理解守護(hù)進(jìn)程、linux內(nèi)核之進(jìn)程的基本概念(進(jìn)程,進(jìn)程組,會話關(guān)系)、PHP多進(jìn)程初探 --- 再次談daemon進(jìn)程

相關(guān)函數(shù)

PCNTL函數(shù)

pcntl_fork ( void ) : int

產(chǎn)生子進(jìn)程分支

此函數(shù)后的代碼,父子進(jìn)程都會執(zhí)行,執(zhí)行順序則是隨機(jī)的。此函數(shù)會在父進(jìn)程和子進(jìn)程內(nèi)產(chǎn)生不同的返回值,子進(jìn)程返回0,父進(jìn)程則返回子進(jìn)程的pid,如果失敗則返回-1,由于父子進(jìn)程都會執(zhí)行后續(xù)代碼,所以我們一般用if來判定哪個(gè)是父進(jìn)程哪個(gè)是子進(jìn)程。

pcntl_wait ( int &$status [, int $options = 0 ] ) : int

用于子進(jìn)程結(jié)束時(shí),回收子進(jìn)程資源

pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] ) : int

同pcntl_wait基本一樣,但是多了指定pid的參數(shù),當(dāng)$pid=-1時(shí),相當(dāng)于pcntl_wait,其它的$pid參數(shù)自行查看文檔

上面兩函數(shù)第二個(gè)參數(shù)$status是個(gè)引用,可以獲取到子進(jìn)程結(jié)束時(shí)的狀態(tài)信息,通過調(diào)用其它函數(shù)來解析status具體含義

上面兩函數(shù)第三個(gè)參數(shù)則比較費(fèi)解,除了0外還有兩個(gè)選項(xiàng)WNOHANG和WUNTRACED。上面兩個(gè)函數(shù)默認(rèn)是阻塞的,直到有子進(jìn)程結(jié)束時(shí),才會有響應(yīng)動作,如果想不阻塞,可以將$options參數(shù)設(shè)置為WNOHANG,當(dāng)沒有子進(jìn)程退出時(shí)不再阻塞等待,而是直接返回0,而如果設(shè)置為WUNTRACED參數(shù)則和設(shè)置為0一樣還是阻塞,但是除了子進(jìn)程結(jié)束會響應(yīng)外SIGTTIN, SIGTTOU, SIGTSTP,SIGSTOP這些信號也會響應(yīng)。

POSIX函數(shù)

posix_getpid ( void ) : int

獲取當(dāng)前進(jìn)程ID,常用于區(qū)分是否為父進(jìn)程

posix_getppid ( void ) : int

獲取父進(jìn)程ID

posix_getuid ( void ) : int

獲取當(dāng)前進(jìn)程的用戶ID

posix_setuid ( int $uid ) : bool

設(shè)置當(dāng)前進(jìn)程的用戶ID

posix_getgid( void ) : int

獲取當(dāng)前進(jìn)程所屬組ID

posix_setgid( int $gid ) : bool

設(shè)置當(dāng)前進(jìn)程組ID

posix_getsid ( int $pid ) : int

獲取某進(jìn)程的會話ID,需要注意的是參數(shù)需要傳遞,可以先通過posix_getpid獲取pid參數(shù),再獲取sid

posix_setsid( void ) : int

設(shè)置當(dāng)前進(jìn)程為會話的領(lǐng)頭進(jìn)程,需要注意參數(shù),只能設(shè)置當(dāng)前的進(jìn)程

posix_getpwuid( int $uid ) : array

根據(jù)用戶ID獲取此用戶的信息,例如用戶的名稱、密碼,組等信息

posix_getpwnam ( string $username ) : array

根據(jù)用戶名獲取此用戶的信息,例如用戶的ID、密碼、組等信息

posix_getgrgid ( int $gid ) : array

根據(jù)組ID獲取此組的信息,例如組名稱、密碼、成員等信息

posix_getgrnam( string $name ) : array

根據(jù)組名稱獲取此組的信息,例如組ID、密碼、成員等信息

posix_initgroups ( string $name , int $base_group_id ) : bool

初始化組清單,將$name所屬的附加組也加入到此進(jìn)程的組權(quán)限中。

這個(gè)函數(shù)不太好理解,因?yàn)楹蛃etgid有些類似。用戶是有附加組的,同一個(gè)用戶可能屬于多個(gè)組,setuid只是設(shè)置用戶ID,setgid是設(shè)置組ID,但用戶ID可能同時(shí)還有其它組的權(quán)限,要想獲取其它組的權(quán)限,則需要運(yùn)行此命令。

相關(guān)代碼

創(chuàng)建子進(jìn)程$pid = pcntl_fork();

//父進(jìn)程和子進(jìn)程都會執(zhí)行下面代碼

if ($pid == -1) {

//錯(cuò)誤處理:創(chuàng)建子進(jìn)程失敗時(shí)返回-1.

die(‘could not fork‘);

} else if ($pid) {

//父進(jìn)程會得到子進(jìn)程號,所以這里是父進(jìn)程執(zhí)行的邏輯

pcntl_wait($status); //等待子進(jìn)程中斷,防止子進(jìn)程成為僵尸進(jìn)程。

} else {

//子進(jìn)程得到的$pid為0, 所以這里是子進(jìn)程執(zhí)行的邏輯。

}

設(shè)置用戶ID和組$user = ‘www‘;

$group = ‘www‘;

// Get uid.

$user_info = posix_getpwnam($user);

if (!$user_info) {

echo "Warning: User {$user} not exsits";

exit;

}

$uid = $user_info[‘uid‘];

// Get gid.

if ($group) {

$group_info = posix_getgrnam($group);

if (!$group_info) {

echo "Warning: Group {$group} not exsits";

exit;

}

$gid = $group_info[‘gid‘];

} else {

$gid = $user_info[‘gid‘];

}

// Set uid and gid.

if ($uid != posix_getuid() || $gid != posix_getgid()) {

if (!posix_setgid($gid) || !posix_initgroups($user_info[‘name‘], $gid) || !posix_setuid($uid)) {

echo "Warning: change gid or uid fail.";

exit;

}

}

需要注意

在fork前的變量,fork后父子都可以引用,fork后可以各自修改,但已經(jīng)是獨(dú)立的會互不影響,在fork后父子各自創(chuàng)建的變量也不會互相影響,如果想要傳遞信息,就需要用到進(jìn)程間的通訊了,可以參考進(jìn)程間通信的方式——信號、管道、消息隊(duì)列、共享內(nèi)存 、PHP多進(jìn)程初探 --- 進(jìn)程間通信二三事。

在循環(huán)中的fork,第一次fork后,會產(chǎn)生兩個(gè)進(jìn)程,而這兩個(gè)進(jìn)程是在循環(huán)中的,所以再次循環(huán)時(shí),這兩個(gè)進(jìn)程都會創(chuàng)建各自的子進(jìn)程,類似細(xì)胞分裂,所以循環(huán)的個(gè)數(shù)會遠(yuǎn)小于實(shí)際產(chǎn)生的子進(jìn)程數(shù)。那如何避免呢,一種方法是讓子進(jìn)程一直while循環(huán),這樣他就無法繼續(xù)執(zhí)行下一次的fork(保險(xiǎn)期間還是加上exit比較好),另一種就是子進(jìn)程處理完后就exit退出,自然是不會執(zhí)行下一次的fork了。

上方POSIX函數(shù)的主要應(yīng)用場景是設(shè)置子進(jìn)程以非root的權(quán)限運(yùn)行,例如我們在nginx中設(shè)置的參數(shù)user:www www,就是在指定子進(jìn)程運(yùn)行的用戶名和用戶組,否則子進(jìn)程也用root來運(yùn)行的話權(quán)限過大,存在安全隱患。

回收子進(jìn)程的幾種方式:

在主進(jìn)程中通過wait或waitpid來阻塞或者是循環(huán)來處理子進(jìn)程回收

通過信號SIGCHLD來實(shí)現(xiàn),每個(gè)子進(jìn)程結(jié)束時(shí)都會發(fā)送SIGCHLD信號,父進(jìn)程進(jìn)行捕捉調(diào)用wait或waitpid來回收

linux下還可以通過直接忽略SIGCHLD來實(shí)現(xiàn):signal(SIGCHLD, SIG_IGN),此時(shí)子進(jìn)程結(jié)束時(shí),直接由內(nèi)核init進(jìn)程來負(fù)責(zé)回收

上面幾種方式看似第一種不太好,因?yàn)橹鬟M(jìn)程都用來處理子進(jìn)程的回收了,就不能做其它的事情了,但實(shí)際上主進(jìn)程本來就是來管理子進(jìn)程的,并沒有多少自己的邏輯,而且越少處理邏輯越安全,所以直接在循環(huán)中處理并沒有什么問題。

關(guān)聯(lián)

上篇:php socket網(wǎng)絡(luò)編程基礎(chǔ)知識(三):stream函數(shù)

下篇:php socket網(wǎng)絡(luò)編程基礎(chǔ)知識(五):信號(未完成)

php socket網(wǎng)絡(luò)編程基礎(chǔ)知識(四):多進(jìn)程

標(biāo)簽:status???傳遞???windows???返回???修改???隊(duì)列???_for???響應(yīng)???關(guān)聯(lián)

總結(jié)

以上是生活随笔為你收集整理的多实例多进程网络编程PHP,php socket网络编程基础知识(四):多进程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。