多实例多进程网络编程PHP,php socket网络编程基础知识(四):多进程
標簽:status???傳遞???windows???返回???修改???隊列???_for???響應???關聯
說明
php在web編程時是不需要考慮多進程的,但整個php流程是涉及到多進程的,只不過nginx、php-fpm幫我們處理好了,我們配置他們參數時就需要設置進程個數相關參數
php在多進程涉及到的是PCNTL擴展和POSIX擴展,這兩個擴展交叉涉及到進程和信號相關,他們只支持Unix平臺,windows平臺不支持,而且只支持cli模式下運行。
php也提供了其它函數來處理多進程的場景,例如exec相關的函數,所以并不是涉及到多進程都需要上方擴展,推薦symfony/process,對php此類相關函數進行的封裝和兼容處理,同時支持linux和windows,非常好用的多進程庫,一般的中小項目完全滿足需求。
我們只從上方擴展中找進程相關的函數來總結,信號相關的在下節中總結
概念
這里涉及到一些linux系統相關的的概念,可能需要先做了解
僵尸進程和孤兒進程,簡單來說就是子進程結束而父進程沒有回收善后處理則產生僵尸進程,而父進程提前結束而子進程還存在則產生孤兒進程,可參考PHP多進程初探 --- 孤兒和僵尸,
用戶(uid)和用戶組(gid),這個大家應該都清楚,創建linux用戶、指定nginx等執行用戶和用戶組、設置文件權限都會用到,還有有效用戶(euid)和有效組(egid),感興趣的可以去自行搜索。
進程(pid,英文:process ID)、父進程(ppid)、進程組(pgid)、會話組(sid),例如我們從終端xshell登陸,就會產生一個會話組,然后我們執行命令,會在會話組下產生進程組,而進程組中就包含各種進程??梢詤⒖紡倪M程組、會話、終端的概念深入理解守護進程、linux內核之進程的基本概念(進程,進程組,會話關系)、PHP多進程初探 --- 再次談daemon進程
相關函數
PCNTL函數
pcntl_fork ( void ) : int
產生子進程分支
此函數后的代碼,父子進程都會執行,執行順序則是隨機的。此函數會在父進程和子進程內產生不同的返回值,子進程返回0,父進程則返回子進程的pid,如果失敗則返回-1,由于父子進程都會執行后續代碼,所以我們一般用if來判定哪個是父進程哪個是子進程。
pcntl_wait ( int &$status [, int $options = 0 ] ) : int
用于子進程結束時,回收子進程資源
pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] ) : int
同pcntl_wait基本一樣,但是多了指定pid的參數,當$pid=-1時,相當于pcntl_wait,其它的$pid參數自行查看文檔
上面兩函數第二個參數$status是個引用,可以獲取到子進程結束時的狀態信息,通過調用其它函數來解析status具體含義
上面兩函數第三個參數則比較費解,除了0外還有兩個選項WNOHANG和WUNTRACED。上面兩個函數默認是阻塞的,直到有子進程結束時,才會有響應動作,如果想不阻塞,可以將$options參數設置為WNOHANG,當沒有子進程退出時不再阻塞等待,而是直接返回0,而如果設置為WUNTRACED參數則和設置為0一樣還是阻塞,但是除了子進程結束會響應外SIGTTIN, SIGTTOU, SIGTSTP,SIGSTOP這些信號也會響應。
POSIX函數
posix_getpid ( void ) : int
獲取當前進程ID,常用于區分是否為父進程
posix_getppid ( void ) : int
獲取父進程ID
posix_getuid ( void ) : int
獲取當前進程的用戶ID
posix_setuid ( int $uid ) : bool
設置當前進程的用戶ID
posix_getgid( void ) : int
獲取當前進程所屬組ID
posix_setgid( int $gid ) : bool
設置當前進程組ID
posix_getsid ( int $pid ) : int
獲取某進程的會話ID,需要注意的是參數需要傳遞,可以先通過posix_getpid獲取pid參數,再獲取sid
posix_setsid( void ) : int
設置當前進程為會話的領頭進程,需要注意參數,只能設置當前的進程
posix_getpwuid( int $uid ) : array
根據用戶ID獲取此用戶的信息,例如用戶的名稱、密碼,組等信息
posix_getpwnam ( string $username ) : array
根據用戶名獲取此用戶的信息,例如用戶的ID、密碼、組等信息
posix_getgrgid ( int $gid ) : array
根據組ID獲取此組的信息,例如組名稱、密碼、成員等信息
posix_getgrnam( string $name ) : array
根據組名稱獲取此組的信息,例如組ID、密碼、成員等信息
posix_initgroups ( string $name , int $base_group_id ) : bool
初始化組清單,將$name所屬的附加組也加入到此進程的組權限中。
這個函數不太好理解,因為和setgid有些類似。用戶是有附加組的,同一個用戶可能屬于多個組,setuid只是設置用戶ID,setgid是設置組ID,但用戶ID可能同時還有其它組的權限,要想獲取其它組的權限,則需要運行此命令。
相關代碼
創建子進程$pid = pcntl_fork();
//父進程和子進程都會執行下面代碼
if ($pid == -1) {
//錯誤處理:創建子進程失敗時返回-1.
die(‘could not fork‘);
} else if ($pid) {
//父進程會得到子進程號,所以這里是父進程執行的邏輯
pcntl_wait($status); //等待子進程中斷,防止子進程成為僵尸進程。
} else {
//子進程得到的$pid為0, 所以這里是子進程執行的邏輯。
}
設置用戶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后可以各自修改,但已經是獨立的會互不影響,在fork后父子各自創建的變量也不會互相影響,如果想要傳遞信息,就需要用到進程間的通訊了,可以參考進程間通信的方式——信號、管道、消息隊列、共享內存 、PHP多進程初探 --- 進程間通信二三事。
在循環中的fork,第一次fork后,會產生兩個進程,而這兩個進程是在循環中的,所以再次循環時,這兩個進程都會創建各自的子進程,類似細胞分裂,所以循環的個數會遠小于實際產生的子進程數。那如何避免呢,一種方法是讓子進程一直while循環,這樣他就無法繼續執行下一次的fork(保險期間還是加上exit比較好),另一種就是子進程處理完后就exit退出,自然是不會執行下一次的fork了。
上方POSIX函數的主要應用場景是設置子進程以非root的權限運行,例如我們在nginx中設置的參數user:www www,就是在指定子進程運行的用戶名和用戶組,否則子進程也用root來運行的話權限過大,存在安全隱患。
回收子進程的幾種方式:
在主進程中通過wait或waitpid來阻塞或者是循環來處理子進程回收
通過信號SIGCHLD來實現,每個子進程結束時都會發送SIGCHLD信號,父進程進行捕捉調用wait或waitpid來回收
linux下還可以通過直接忽略SIGCHLD來實現:signal(SIGCHLD, SIG_IGN),此時子進程結束時,直接由內核init進程來負責回收
上面幾種方式看似第一種不太好,因為主進程都用來處理子進程的回收了,就不能做其它的事情了,但實際上主進程本來就是來管理子進程的,并沒有多少自己的邏輯,而且越少處理邏輯越安全,所以直接在循環中處理并沒有什么問題。
關聯
上篇:php socket網絡編程基礎知識(三):stream函數
下篇:php socket網絡編程基礎知識(五):信號(未完成)
php socket網絡編程基礎知識(四):多進程
標簽:status???傳遞???windows???返回???修改???隊列???_for???響應???關聯
總結
以上是生活随笔為你收集整理的多实例多进程网络编程PHP,php socket网络编程基础知识(四):多进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java高级语法笔记-文本文件的按行读取
- 下一篇: WEB安全基础-命令注入