最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

php超詳細(xì)講解命名管道

 更新時(shí)間:2022年07月27日 08:31:42   作者:大雷編程  
這篇文章主要介紹了php中通過命名管道實(shí)現(xiàn)跨語言進(jìn)程間通信的案例,具有一定借鑒價(jià)值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下

進(jìn)程間為什么要通信

進(jìn)程間通信的目的:

  • 數(shù)據(jù)傳輸:一個(gè) 進(jìn)程需要將它的數(shù)據(jù) 發(fā)送給另一個(gè)進(jìn)程。
  • 通知事件:一個(gè)進(jìn)程需要向另一個(gè)或一組進(jìn)程 發(fā)送消息,通知它(它們)發(fā)生了 某種事件(如進(jìn)程終止時(shí)要通知父進(jìn)程)。
  • 資源共享:多個(gè)進(jìn)程之間 共享同樣的資源 。為了做到這一點(diǎn),需要內(nèi)核提供互斥和同步機(jī)制。
  • 進(jìn)程控制:有些進(jìn)程 希望完全控制另一個(gè)進(jìn)程的執(zhí)行 (如 Debug 進(jìn)程),此時(shí)控制進(jìn)程希望能夠攔截另一個(gè)進(jìn)程的所有狀態(tài)信息

進(jìn)程不是孤立的,一個(gè)足夠大的項(xiàng)目絕對(duì)不是單一的進(jìn)程可以支撐的起的。所以我們需要進(jìn)程間通信,來滿足不同進(jìn)程間信息交互與傳遞的需求。

進(jìn)程間通信本質(zhì)上是進(jìn)程與進(jìn)程之間交換數(shù)據(jù)的手段。

進(jìn)程如何實(shí)現(xiàn)通信

每個(gè)進(jìn)程的用戶地址空間都是獨(dú)立的(進(jìn)程通過虛擬內(nèi)存地址達(dá)到進(jìn)程相互隔離),一般而言是不能互相訪問的,進(jìn)程之間要通信必須通過內(nèi)核,也就是說操作內(nèi)核提供一個(gè)緩沖區(qū),用戶進(jìn)程操作這個(gè)緩沖區(qū)【讀寫數(shù)據(jù)】來實(shí)現(xiàn)通信。

常見進(jìn)程通信方式

今天我們要學(xué)習(xí)的是管道中的命名管道

管道概念

其實(shí)管道一共有兩種,一種是匿名管道,它的特點(diǎn)是只能用于具有共同祖先的進(jìn)程(具有親緣關(guān)系的進(jìn)程)之間進(jìn)行通信;比如父子進(jìn)程,通常,一個(gè)匿名管道由一個(gè)進(jìn)程創(chuàng)建,然后該進(jìn)程調(diào)用fork,此后父、子進(jìn)程之間就可應(yīng)用該管道。

對(duì)于匿名管道,它的通信范圍是存在父子關(guān)系的進(jìn)程。因?yàn)楣艿罌]有實(shí)體,也就是沒有管道文件,只能通過 fork 來復(fù)制父進(jìn)程 fd 文件描述符,來達(dá)到通信的目的。

第二種是命名管道可以實(shí)現(xiàn)兩個(gè)不相關(guān)進(jìn)程之間進(jìn)行數(shù)據(jù)交互,也能實(shí)現(xiàn)父子進(jìn)程之間數(shù)據(jù)交互。命名管道是一種特殊類型的文件,有實(shí)體

對(duì)于命名管道,它可以在不相關(guān)的進(jìn)程間也能相互通信。因?yàn)槊艿溃崆皠?chuàng)建了一個(gè)類型為管道的設(shè)備文件,在進(jìn)程里只要使用這個(gè)設(shè)備文件,就可以相互通信。

由于php擴(kuò)展并沒有提供匿名管道的封裝,只提供了命名管道的,所有我們先不講匿名管道,有興趣的自行了解

命名管道實(shí)現(xiàn)

不管是匿名管道還是命名管道,進(jìn)程寫入的數(shù)據(jù)都是緩存在內(nèi)核中,另一個(gè)進(jìn)程讀取數(shù)據(jù)時(shí)候自然也是從內(nèi)核中獲取,同時(shí)通信數(shù)據(jù)都遵循先進(jìn)先出原則,類似于隊(duì)列

posix_mkfifo函數(shù)

php 通過 posix_mkfifo 函數(shù)創(chuàng)建命名管道文件

<?php
//定義管道文件
$file = 'fifo_dalei';
//posix_access() 函數(shù)檢測(cè)管道文件是否存在,如果不存在使用posix_mkfifo() 函數(shù)創(chuàng)建一個(gè)命名管道文件
if(!posix_access($file, POSIX_F_OK)){
    if(posix_mkfifo($file,0666)){
        echo "命名管道創(chuàng)建成功\n";
    }
}

執(zhí)行代碼我們就得到了創(chuàng)建出來的管道文件 fifo_dalei ,我們查看文件權(quán)限位以 p 開頭就表示這個(gè)文件是一個(gè)管道文件,當(dāng)然我們也可以使用 file 命令查看fifo_dalei 文件類型是管道類型

我們可以直接在終端操作讀寫這個(gè)命名管道文件

比如:我們打開兩個(gè)終端,A終端與B終端,A終端負(fù)責(zé)讀命名管道中的數(shù)據(jù),B終端負(fù)責(zé)往命名管道寫入數(shù)據(jù)

我們通過 cat 命令 讀取命名管道,如果命名管道沒有數(shù)據(jù) cat fifo_dalei 命令會(huì)阻塞住,直到有數(shù)據(jù)寫入命名管道,cat fifo_dalei 才會(huì)輸出數(shù)據(jù)內(nèi)容并結(jié)束,反過來如果先將數(shù)據(jù)寫入命名管道,卻沒有另一個(gè)進(jìn)程讀取命名管道的內(nèi)容,寫入命令依然會(huì)阻塞。

由此可以發(fā)現(xiàn),管道這種通信方式效率低,不適合進(jìn)程間頻繁地交換數(shù)據(jù)。當(dāng)然,它的好處,自然就是簡(jiǎn)單,同時(shí)也我們很容易得知管道里的數(shù)據(jù)已經(jīng)被另一個(gè)進(jìn)程讀取了。

那么在php中我們?nèi)绾问褂妹艿牢募兀旅嫖覀円愿缸舆M(jìn)程通信為例

<?php
// 定義命名管道文件
$file = 'fifo_dalei';
// posix_access 函數(shù)檢測(cè)當(dāng)前文件是否存在
if(!posix_access($file, POSIX_F_OK)){
//posix_mkfifo 函數(shù)創(chuàng)建命名管道
    if(posix_mkfifo($file,0666)){
        echo "命名管道創(chuàng)建成功\n";
    }
}
// fork 創(chuàng)建子進(jìn)程
$pid = pcntl_fork();
if($pid == 0){//子進(jìn)程執(zhí)行邏輯
	// 用讀方式打開命名管道,需要注意的是如果命名管道內(nèi)沒有數(shù)據(jù),fopen 函數(shù)會(huì)阻塞
    $fd = fopen($file, 'r');
    // fread 函數(shù) 讀取命名管道,10個(gè)字節(jié)長(zhǎng)度數(shù)據(jù)
    $data = fread($fd,10);
    if($data){
            fprintf(STDOUT,"read process pid = %d, recv:%s\n",getmypid(),$data);
    }
    exit(0);
}
// 用寫方式打開命名管道
$fd = fopen($file, 'w');
// 往命名管道寫入數(shù)據(jù) 'dalei' 寫入的長(zhǎng)度為5
$len = fwrite($fd,'dalei',5);
fprintf(STDOUT,"write process pid = %d, write len=%d\n",posix_getpid(),$len);
// 關(guān)閉管道文件
fclose($fd);
//回收?qǐng)?zhí)行完畢退出子進(jìn)程,防止僵尸進(jìn)程
$pid = pcntl_wait($status);
if($pid > 0){
    fprintf(STDOUT,"exit process pid = %d\n",$pid);
}

分析上面代碼,首先父進(jìn)程32023 寫入數(shù)據(jù)dalei到命名管道,子進(jìn)程 32024 讀取命名管道中父進(jìn)程寫入的數(shù)據(jù),然后 32024 子進(jìn)程退出。

需要注意的是 fopen() 函數(shù)打開命名管道必須讀端寫端都打開,不然 fopen() 函數(shù)會(huì)阻塞

上面我們通過命令操作管道發(fā)現(xiàn),管道內(nèi)必須有內(nèi)容,才能讀取管道,不然會(huì)阻塞,php操作管道也同樣有這個(gè)問題,看下面代碼,我們通過 while 不停循環(huán)讀取管道內(nèi)容,但是寫數(shù)據(jù)端寫入一次會(huì)發(fā)生什么事情呢?

<?php
// 定義命名管道文件
$file = 'fifo_dalei';
// posix_access 函數(shù)檢測(cè)當(dāng)前文件是否存在
if(!posix_access($file, POSIX_F_OK)){
//posix_mkfifo 函數(shù)創(chuàng)建命名管道
    if(posix_mkfifo($file,0666)){
        echo "命名管道創(chuàng)建成功\n";
    }
}
// fork 創(chuàng)建子進(jìn)程
$pid = pcntl_fork();
if($pid == 0){//子進(jìn)程執(zhí)行邏輯
	// 用讀方式打開命名管道,需要注意的是如果命名管道內(nèi)沒有數(shù)據(jù),fopen 函數(shù)會(huì)阻塞
    $fd = fopen($file, 'r');
    while(1){
    // fread 函數(shù) 讀取命名管道,10個(gè)字節(jié)長(zhǎng)度數(shù)據(jù)
    $data = fread($fd,10);
    if($data){
            fprintf(STDOUT,"read process pid = %d, recv:%s\n",getmypid(),$data);
    }
    echo "hello\n";
     sleep(2);
    }
    exit(0);
}
// 用寫方式打開命名管道
$fd = fopen($file, 'w');
// 往命名管道寫入數(shù)據(jù) 'dalei' 寫入的長(zhǎng)度為5
$len = fwrite($fd,'dalei',5);
fprintf(STDOUT,"write process pid = %d, write len=%d\n",posix_getpid(),$len);
// 關(guān)閉管道文件
#fclose($fd);
//回收?qǐng)?zhí)行完畢退出子進(jìn)程,防止僵尸進(jìn)程
$pid = pcntl_wait($status);
if($pid > 0){
    fprintf(STDOUT,"exit process pid = %d\n",$pid);
}

通過運(yùn)行上面代碼,當(dāng)父進(jìn)程只寫入一次,子進(jìn)程循環(huán)讀,由于命名管道內(nèi)無數(shù)據(jù)會(huì)造成 fread() 函數(shù)阻塞,無法往下執(zhí)行也就無法打印出 hello,如何以非阻塞的方式讀取數(shù)據(jù)呢?

下面我們就來介紹 stream_set_blocking() 函數(shù)實(shí)現(xiàn)非阻塞讀命名管道,即命名管道無數(shù)據(jù)立即返回,并不會(huì)阻塞在fread() 函數(shù)

<?php
// 定義命名管道文件
$file = 'fifo_dalei';
// posix_access 函數(shù)檢測(cè)當(dāng)前文件是否存在
if(!posix_access($file, POSIX_F_OK)){
//posix_mkfifo 函數(shù)創(chuàng)建命名管道
    if(posix_mkfifo($file,0666)){
        echo "命名管道創(chuàng)建成果\n";
    }
}
// fork 創(chuàng)建子進(jìn)程
$pid = pcntl_fork();
if($pid == 0){//子進(jìn)程執(zhí)行邏輯
	// 用讀方式打開命名管道,需要注意的是如果命名管道內(nèi)沒有數(shù)據(jù),fopen 函數(shù)會(huì)阻塞
    $fd = fopen($file, 'r');
    //設(shè)置非阻塞讀取命名管道
    stream_set_blocking($fd,0);
    while(1){
    // fread 函數(shù) 讀取命名管道,10個(gè)字節(jié)長(zhǎng)度數(shù)據(jù)
    $data = fread($fd,10);
    if($data){
            fprintf(STDOUT,"read process pid = %d, recv:%s\n",getmypid(),$data);
    }
    echo "hello\n";
    sleep(2);
    }
    exit(0);
}
// 用寫方式打開命名管道
$fd = fopen($file, 'w');
// 往命名管道寫入數(shù)據(jù) 'dalei' 寫入的長(zhǎng)度為5
$len = fwrite($fd,'dalei',5);
fprintf(STDOUT,"write process pid = %d, write len=%d\n",posix_getpid(),$len);
// 關(guān)閉管道文件
#fclose($fd);
//回收?qǐng)?zhí)行完畢退出子進(jìn)程,防止僵尸進(jìn)程
$pid = pcntl_wait($status);

if($pid > 0){
    fprintf(STDOUT,"exit process pid = %d\n",$pid);
}

還有個(gè)需要注意的知識(shí)點(diǎn),當(dāng)寫端寫入數(shù)據(jù)的過程中,如果讀端退出,寫入數(shù)據(jù)將失敗,并且產(chǎn)生中斷信號(hào) SIGPIPE, 下面是實(shí)驗(yàn)代碼

<?php
// 定義命名管道文件
$file = 'fifo_dalei';
// posix_access 函數(shù)檢測(cè)當(dāng)前文件是否存在
if(!posix_access($file, POSIX_F_OK)){
//posix_mkfifo 函數(shù)創(chuàng)建命名管道
    if(posix_mkfifo($file,0666)){
        echo "命名管道創(chuàng)建成果\n";
    }
}
// 安裝信號(hào)處理器,處理捕獲信號(hào)
pcntl_signal(SIGPIPE,function($signo){
fprintf(STDOUT,"signo=%d\n",$signo);
});
// fork 創(chuàng)建子進(jìn)程
$pid = pcntl_fork();
if($pid == 0){//子進(jìn)程執(zhí)行邏輯
	// 用讀方式打開命名管道,需要注意的是如果命名管道內(nèi)沒有數(shù)據(jù),fopen 函數(shù)會(huì)阻塞
    $fd = fopen($file, 'r');
    //設(shè)置非阻塞讀取命名管道
    stream_set_blocking($fd,0);
    $i = 0;
    while(1){
    // fread 函數(shù) 讀取命名管道,10個(gè)字節(jié)長(zhǎng)度數(shù)據(jù)
    $data = fread($fd,10);
    if($data){
    	$i++;
    	if($i > 2){
    		fclose($fd);
    		break;
    	}
            fprintf(STDOUT,"read process pid = %d, recv:%s\n",getmypid(),$data);
    }
    sleep(2);
    }
    exit(0);
}
// 用寫方式打開命名管道
$fd = fopen($file, 'w');
stream_set_blocking($fd,0);
while(1){
// 信號(hào)分發(fā)(沒有這個(gè)函數(shù),信號(hào)無法被捕獲)
pcntl_signal_dispatch();
// 往命名管道寫入數(shù)據(jù) 'dalei' 寫入的長(zhǎng)度為5
$len = fwrite($fd,'dalei',5);
fprintf(STDOUT,"write process pid = %d, write len=%d\n",posix_getpid(),$len);
sleep(2);
}
// 關(guān)閉管道文件
fclose($fd);
//回收?qǐng)?zhí)行完畢退出子進(jìn)程,防止僵尸進(jìn)程
$pid = pcntl_wait($status);
if($pid > 0){
    fprintf(STDOUT,"exit process pid = %d\n",$pid);
}

通過分析代碼我們得知,我們定義了一個(gè) $i 變量 用于累加,當(dāng)累加數(shù)大于2,也就是read執(zhí)行超過兩次后讀進(jìn)程退出,寫進(jìn)程write將無法再向命名管道寫入數(shù)據(jù),并且產(chǎn)生信號(hào)數(shù)為13的中斷信號(hào)

使用 kill -l 查看linux 中所有信號(hào)

無血緣進(jìn)程間通信

寫端

<?php
$file = 'fifo_dalei';
if(!posix_access($file,POSIX_F_OK)){
    if(!posix_mkfifo($file,0666)){
    }
}
$fd = fopen($file,'w');
while(1){
	//獲取終端輸入數(shù)據(jù),大小限制1280字節(jié)
    $data = fgets(STDIN,1280);
    // 寫入數(shù)據(jù)到命名管道,數(shù)據(jù)長(zhǎng)度限制為10個(gè)字節(jié)
    $len = fwrite($fd,$data,10);
    fprintf(STDOUT,"pid=%d, write len = %d\n",posix_getpid(),$len);
}
fclose($fd);

讀端 (一定要設(shè)置非阻塞讀,不然寫端,寫入數(shù)據(jù)讀端無法讀取,只有寫端進(jìn)程退出才,讀端才能全部讀取出來)

<?php
$file = 'fifo_dalei';
if(!posix_access($file,POSIX_F_OK)){
    if(posix_mkfifo($file,0666)){

    }
}
$fd = fopen($file,'r');
//設(shè)置非阻塞讀
stream_set_blocking($fd,0);
while(1){
//讀取命名管道內(nèi)容,讀取長(zhǎng)度限制為128字節(jié)
$data = fread($fd,128);
if($data){
    fprintf(STDOUT,"pid=%d,data=%s\n",posix_getpid(),$data);
}
}
fclose($fd);

通過上面的學(xué)習(xí),我們已經(jīng)了解了命名管道的用法與實(shí)現(xiàn),當(dāng)然大家還可以自己動(dòng)手嘗試編寫命名管道的多種組合方式。比如說,多個(gè)讀端,一個(gè)寫端,讀端是同時(shí)能讀取到寫入內(nèi)容還是,一個(gè)能獲取,一個(gè)獲取不到,又或者多個(gè)寫端一個(gè)讀端會(huì)發(fā)生什么情況,這些大家都可以自己實(shí)現(xiàn)看看,畢竟實(shí)踐出真知,不動(dòng)手只聽別人說可不行哦!

到此這篇關(guān)于php超詳細(xì)講解命名管道的文章就介紹到這了,更多相關(guān)php命名管道內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • PHP實(shí)現(xiàn)APP微信支付的實(shí)例講解

    PHP實(shí)現(xiàn)APP微信支付的實(shí)例講解

    下面小編就為大家分享一篇PHP實(shí)現(xiàn)APP微信支付的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • 一文看懂PHP進(jìn)程管理器php-fpm

    一文看懂PHP進(jìn)程管理器php-fpm

    這篇文章主要介紹了PHP進(jìn)程管理器php-fpm的配置說明,文中代碼簡(jiǎn)單易懂,方便大家更好的理解,有興趣的小伙伴快來了解下
    2020-06-06
  • 探討fckeditor在Php中的配置詳解

    探討fckeditor在Php中的配置詳解

    本篇文章是對(duì)fckeditor在Php中的配置進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • php查看當(dāng)前Session的ID實(shí)例

    php查看當(dāng)前Session的ID實(shí)例

    這篇文章主要介紹了php查看當(dāng)前Session的ID的方法,實(shí)例分析了兩種常見的獲取session中ID的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-03-03
  • web php include攻防世界php安全示例詳解

    web php include攻防世界php安全示例詳解

    這篇文章主要介紹了php安全防護(hù)的防注入include文件示例詳解,有需要的朋友可以借鑒參考下, 希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-10-10
  • php自動(dòng)跳轉(zhuǎn)中英文頁面

    php自動(dòng)跳轉(zhuǎn)中英文頁面

    當(dāng)來訪者瀏覽器語言是中文就進(jìn)入中文版面 國(guó)外的用戶默認(rèn)瀏覽器不是中文的就跳轉(zhuǎn)英文頁面
    2008-07-07
  • php字符串過濾與替換小結(jié)

    php字符串過濾與替換小結(jié)

    這篇文章主要介紹了php字符串過濾與替換,實(shí)例總結(jié)了php實(shí)現(xiàn)字符串過濾與替換的技巧,需要的朋友可以參考下
    2015-01-01
  • php中Snoopy類用法實(shí)例

    php中Snoopy類用法實(shí)例

    這篇文章主要介紹了php中Snoopy類用法,實(shí)例分析了使用Snoopy類實(shí)現(xiàn)頁面抓取的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • php表單提交問題的解決方法

    php表單提交問題的解決方法

    不是第一次寫表單提交了,但還是遇到了無法解決的問題。研究了將近一天,問了N多網(wǎng)友,最終解決了問題,過程頗為曲折。感謝大家的幫助。
    2011-04-04
  • PHP自動(dòng)生成后臺(tái)導(dǎo)航網(wǎng)址的最佳方法

    PHP自動(dòng)生成后臺(tái)導(dǎo)航網(wǎng)址的最佳方法

    寫過很多種不同的后臺(tái)導(dǎo)航寫法最終積累了這種最寫法,算是最好的吧,個(gè)人感覺還算是不錯(cuò)的,喜歡的朋友可以參考下
    2013-08-08

最新評(píng)論

临沭县| 东阳市| 昌黎县| 青龙| 南雄市| 墨脱县| 安泽县| 视频| 双江| 阆中市| 中江县| 宁河县| 海城市| 福清市| 秭归县| 广饶县| 隆林| 洞口县| 海原县| 双辽市| 瑞金市| 柳林县| 临邑县| 饶平县| 景宁| 塔河县| 富川| 林芝县| 宁阳县| 馆陶县| 上高县| 南涧| 井冈山市| 武安市| 海门市| 冕宁县| 西城区| 西乡县| 杭锦后旗| 枣庄市| 青州市|