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

php消息隊(duì)列實(shí)現(xiàn)詳解

 更新時(shí)間:2022年08月11日 14:50:14   作者:大雷編程  
消息隊(duì)列技術(shù)是分布式應(yīng)用間交換信息的一種技術(shù)。消息隊(duì)列可駐留在內(nèi)存或磁盤上,隊(duì)列存儲(chǔ)消息直到它們被應(yīng)用程序讀出。通過消息隊(duì)列,應(yīng)用程序可獨(dú)立地執(zhí)行,它們不需要知道彼此的位置、或在繼續(xù)執(zhí)行前不需要等待接收程序接收此消息

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

System V IPC 總的包括:消息隊(duì)列,共享內(nèi)存、信號(hào)量。

IPC(內(nèi)部進(jìn)程間通信)的使用注意:

  • IPC資源僅在本機(jī)中使用,不能夠跨網(wǎng)絡(luò)使用(其實(shí)進(jìn)程間通信方式除了socket 通信方式其他都是僅在本機(jī)中使用)。
  • IPC的資源生存周期與內(nèi)核相同。除非刪除,不然會(huì)與系統(tǒng)的生存周期相同。(也就是說如果你不主動(dòng)刪除創(chuàng)建的ipc資源,那么它會(huì)一直存在,除非系統(tǒng)關(guān)機(jī),它才會(huì)被清除)
  • (重要)每個(gè)IPC都有一個(gè)關(guān)鍵字key。每個(gè)IPC資源都有唯一的整型標(biāo)識(shí)符,進(jìn)程可以使用id對(duì)此資源進(jìn)行訪問。

系統(tǒng)V IPC消息隊(duì)列

消息隊(duì)列實(shí)際上是一個(gè)隊(duì)列,由內(nèi)核維護(hù),使用msgget (msgget() 函數(shù)是linux系統(tǒng)調(diào)用函數(shù),由c語言編寫) 函數(shù)來創(chuàng)建一個(gè)消息隊(duì)列,創(chuàng)建成功返回隊(duì)列 ID

在php 中通過封裝 system V IPC 函數(shù)來實(shí)現(xiàn)操作消息隊(duì)列,共享內(nèi)存,與信號(hào)量。我們可以通過php官方文檔上查看這些函數(shù)的定義,其中msg_ 為首的函數(shù)是用來操作消息隊(duì)列,sem_ 為首的函數(shù)是對(duì)信號(hào)量操作,shm_ 為首的函數(shù)是對(duì)共享內(nèi)存的操作

其實(shí) php 這些進(jìn)程擴(kuò)展說到底就是對(duì) linux c 系統(tǒng)調(diào)用函數(shù)與c標(biāo)準(zhǔn)函數(shù)庫的封裝,然后在加一點(diǎn)php語言自己的處理,封裝成新的函數(shù)供 廣大 phper 調(diào)用,只要在linux 下運(yùn)行 不管你是 GO, JAVA ,python 其實(shí)都是對(duì)系統(tǒng)調(diào)用函數(shù)的封裝,只是封裝后的名字不同,但是調(diào)用的都是linux 內(nèi)核提供的同一套接口

php創(chuàng)建一個(gè)消息隊(duì)列

<?php
$key = ftok('demo1.php',"x");//將文件與ID轉(zhuǎn)換為一個(gè)key,這個(gè)文件只要真實(shí)存在就行,沒有特殊限制,一般都指定當(dāng)前文件名
$msqid = msg_get_queue($key);// 創(chuàng)建一個(gè)消息隊(duì)列,返回一個(gè)資源id
echo msg_send($msqid,1,"hello"); //往消息隊(duì)列寫入一條數(shù)據(jù) hello 到隊(duì)列中
echo $msqid; // 輸出資源id

如何查看創(chuàng)建的消息隊(duì)列呢?

我們可用通過linux 提供的 ipcs 命令查看

如圖,第一列 Message Queues 代表消息隊(duì)列

keymsqidownerpermsused-bytesmessages
0x7801620f5root666121
外部標(biāo)識(shí)由調(diào)用函數(shù)時(shí)傳入消息隊(duì)列標(biāo)識(shí)id(用于進(jìn)程內(nèi)部通訊)每個(gè)隊(duì)列都有唯一標(biāo)識(shí),用于區(qū)分不同消息隊(duì)列創(chuàng)建消息隊(duì)列用戶操作權(quán)限位消息隊(duì)列使用了多少字節(jié)消息隊(duì)列有多少條消息

通過表格分析我們剛剛創(chuàng)建的消息隊(duì)列是一個(gè),消息標(biāo)識(shí)符為5 創(chuàng)建用戶為root ,操作權(quán)限為666,寫入了一條數(shù)據(jù),占用了12個(gè)字節(jié)的隊(duì)列。

看到這,大家可能發(fā)現(xiàn)兩個(gè)問題?

第一個(gè)問題:

為什么我調(diào)用 php 函數(shù) msg_get_queue() 創(chuàng)建消息隊(duì)列返回的不是消息隊(duì)列標(biāo)識(shí)符5,而是 Resource id #4

因?yàn)橹罢f過 php 函數(shù)其實(shí)是對(duì)linux c 系統(tǒng)調(diào)用函數(shù)的封裝,也就是說 msg_get_queue 函數(shù) 其實(shí)是對(duì) msgget 系統(tǒng)調(diào)用函數(shù)的封裝,調(diào)用msgget 函數(shù)的返回內(nèi)容應(yīng)該是 消息隊(duì)列標(biāo)識(shí)id,而現(xiàn)在封裝 msgget 函數(shù)的 msg_get_queue 函數(shù)返回的卻是資源描述符,這是為什么?

這其實(shí)就是php內(nèi)部做了處理,返回資源描述符,使得 msg_get_queue 可以配合其他php

函數(shù)一起使用,但內(nèi)部調(diào)用msgget 函數(shù)返回的一定是 5,也就是消息隊(duì)列標(biāo)識(shí)符

如果不相信可使用 linux 下提供的 strace 工具 跟蹤系統(tǒng)調(diào)用。

第二個(gè)問題

通過php函數(shù) msg_send 寫入了一條數(shù)據(jù),數(shù)據(jù)內(nèi)容為 ”hello“ 字節(jié)長度應(yīng)該是5個(gè)字節(jié),但是消息隊(duì)列占用的字節(jié)長度缺少12個(gè)字節(jié)?

這是因?yàn)閜hp 內(nèi)部實(shí)現(xiàn)對(duì)寫入數(shù)據(jù)做了序列化操作,導(dǎo)致寫入消息隊(duì)列的字節(jié)長度為12而不是5個(gè)字節(jié)長度

<?php
$a = serialize("hello");
echo 'hello 序列化長度:'.strlen($a)."\n";
echo 'hello 序列化內(nèi)容:'.$a."\n";
echo "hello 未序列化長度:".strlen("hello")."\n";

當(dāng)然如果你不想 msg_send 函數(shù)寫入隊(duì)列前對(duì)數(shù)據(jù)進(jìn)行序列化,可以把第3個(gè)參數(shù)設(shè)置為false,不過需要注意的是,如果寫入數(shù)據(jù)不進(jìn)行序列化,那么使用 msg_receive 函數(shù)讀取隊(duì)列數(shù)據(jù)時(shí)也必須設(shè)置為不反序列化操作,不然會(huì)引發(fā)錯(cuò)誤

讀取隊(duì)列內(nèi)容

<?php
$key = ftok('demo1.php',"x");//將文件與ID轉(zhuǎn)換為一個(gè)key
$msqid = msg_get_queue($key);//消息隊(duì)列如果已創(chuàng)建,直接返回同一個(gè)資源描述符
//第一個(gè)參數(shù)資源描述符,第二個(gè)參數(shù)一般為0,表示從隊(duì)列第一條讀取,或者設(shè)置與msg_send函數(shù)第二個(gè)參數(shù)一致,第三個(gè)參數(shù)設(shè)置緩沖區(qū)長度,注意msg_send 函數(shù)默認(rèn)會(huì)序列化數(shù)據(jù),msg_receive函數(shù)默認(rèn)會(huì)將讀取數(shù)據(jù)反序列化,如果緩沖區(qū)設(shè)置過小會(huì)反序列化失敗
msg_receive($msqid,1,$received_message_type,1024,$message);//讀取消息隊(duì)列數(shù)據(jù),逐條讀取,
echo $message.PHP_EOL;

成功從消息隊(duì)列中讀取出一條數(shù)據(jù),內(nèi)容hello

因?yàn)橄㈥?duì)列內(nèi)容被讀取,消息隊(duì)列占用字節(jié)被清空為0,消息隊(duì)列消息條數(shù)也為0

通過消息隊(duì)列的讀寫操作我們發(fā)現(xiàn),他與上一篇的管道有什么區(qū)別?

消息隊(duì)列不像管道通信寫入數(shù)據(jù),必須讀端要打開,讀數(shù)據(jù),寫端必須要打開,不然會(huì)阻塞無法通信,消息隊(duì)列可以隨時(shí)往隊(duì)列寫入數(shù)據(jù),讀取數(shù)據(jù)

關(guān)閉序列化功能

寫端

<?php
$key = ftok('demo3.php',"x");//將文件與ID轉(zhuǎn)換為一個(gè)key,這個(gè)文件只要真實(shí)存在就行,沒有特殊限制,一般都指定當(dāng)前文件名
$msqid = msg_get_queue($key);// 創(chuàng)建一個(gè)消息隊(duì)列,返回一個(gè)資源id
// 第一個(gè)參數(shù)資源id,第二個(gè)參數(shù)消息類型,必須大于0,第三個(gè)參數(shù)寫入隊(duì)列內(nèi)容,取消序列化操作
echo msg_send($msqid,1,"hello",false); //往消息隊(duì)列寫入一條數(shù)據(jù) hello 到隊(duì)列中

因?yàn)闆]有對(duì)寫入數(shù)據(jù)進(jìn)行序列化操作,消息隊(duì)列占用的字節(jié)長度變成了5個(gè)字節(jié)。

讀端

<?php
$key = ftok('demo3.php',"x");//將文件與ID轉(zhuǎn)換為一個(gè)key
$msqid = msg_get_queue($key);
//第一個(gè)參數(shù)資源描述符
//第二個(gè)參數(shù)一般為0,表示從隊(duì)列第一條讀取,或者設(shè)置與msg_send函數(shù)第二個(gè)參數(shù)一致
// 第三個(gè)參數(shù)是msg_send函數(shù)的第二個(gè)參數(shù)的值,也就是發(fā)送消息的消息類型
//第四個(gè)參數(shù)設(shè)置接收緩沖區(qū)長度,如果設(shè)置過小會(huì)反序列化失敗【如果使用序列化功能時(shí)候】
//當(dāng)接收緩沖區(qū)大小設(shè)置過小并且關(guān)閉了反序列化【發(fā)送端發(fā)送數(shù)據(jù)也關(guān)閉了】,但是發(fā)送的數(shù)據(jù)超過了設(shè)置的長度,就會(huì)被截?cái)?,并且額外的數(shù)據(jù)會(huì)被丟棄,必須設(shè)置第五個(gè)參數(shù)才有效
// 第五個(gè)參數(shù) flags 標(biāo)志符
msg_receive($msqid,0,$received_message_type,1,$message,false,MSG_NOERROR);
echo $message.PHP_EOL;

只讀取到一個(gè)h? 是因?yàn)榻邮芫彌_區(qū)長度設(shè)置為1個(gè)字節(jié),所以只接收到一個(gè)字節(jié),其它部分被丟棄。

非阻塞讀取消息隊(duì)列

當(dāng)隊(duì)列內(nèi)沒有數(shù)據(jù),讀取隊(duì)列msg_receive函數(shù)是會(huì)阻塞的如何讓隊(duì)列無數(shù)據(jù)讀端也不阻塞繼續(xù)往下執(zhí)行,可以通過 設(shè)置 flags 標(biāo)志符 為 MSG_IPC_NOWAIT,該標(biāo)志符作用是,不管隊(duì)列有無數(shù)據(jù)立即返回結(jié)果

<?php
$key = ftok('demo5.php',"x");//將文件與ID轉(zhuǎn)換為一個(gè)key
$msqid = msg_get_queue($key);
// fork 一個(gè)子進(jìn)程
$pid = pcntl_fork();
if($pid == 0){
    while(1){
    // MSG_IPC_NOWAIT【啟用非阻塞】 msg_receive 函數(shù)其實(shí)是封裝 linux c msgrcv 系統(tǒng)調(diào)用函數(shù),如果設(shè)置為非阻塞,函數(shù)調(diào)用次數(shù)非常高,會(huì)非常消耗cpu資源
    //阻塞模式調(diào)用函數(shù)次數(shù)低,有數(shù)據(jù)才返回,對(duì)cpu友好
        $ret = msg_receive($msqid,0,$msgType,1024,$msg,true,MSG_IPC_NOWAIT,$error_code);
        if($error_code != MSG_ENOMSG){
            echo $msg."\n";
        }
        sleep(2);
        echo "go"."\n";
    }
    exit(0);
}

父子進(jìn)程消息隊(duì)列通信

<?php
$key = ftok('demo5.php',"x");//將文件與ID轉(zhuǎn)換為一個(gè)key
$msqid = msg_get_queue($key);
$pid = pcntl_fork();
if($pid == 0){
    while(1){
        $ret = msg_receive($msqid,0,$msgType,1024,$msg,true,MSG_IPC_NOWAIT,$error_code);
        if($error_code != MSG_ENOMSG){
            echo $msg."\n";
        }
    }
    exit(0);
}
$i = 1;
while(1){
    msg_send($msqid,2,"hello world",true);
    sleep(2);
    if($i++ == 3){
    	// 殺死子進(jìn)程
        posix_kill($pid,SIGILL);
        break;
    }
}
//子進(jìn)程退出回收子進(jìn)程,防止孤兒進(jìn)程
$pid = pcntl_wait($status);
if($pid > 0)
{
    echo "exit pid=".$pid."\n";
}

刪除消息隊(duì)列

<?php
$key = ftok('demo5.php',"x");//將文件與ID轉(zhuǎn)換為一個(gè)key
$msqid = msg_get_queue($key);
$pid = pcntl_fork();
if($pid == 0){
    while(1){
        $ret = msg_receive($msqid,0,$msgType,1024,$msg,true,MSG_IPC_NOWAIT,$error_code);
        if($error_code != MSG_ENOMSG){
            echo $msg."\n";
        }

    }
    exit(0);
}
$i = 1;
while(1){
    msg_send($msqid,2,"hello world",true);
    sleep(2);
    if($i++ == 3){
    	// 殺死子進(jìn)程
        posix_kill($pid,SIGILL);
        break;
    }
}
//子進(jìn)程退出回收子進(jìn)程,防止孤兒進(jìn)程
$pid = pcntl_wait($status);
if($pid > 0)
{
    echo "exit pid=".$pid."\n";
}
//msg_remove_queue 函數(shù)移除消息隊(duì)列
if(msg_remove_queue($msqid)){
    echo "remove ok\n";
}

讀取3次隊(duì)列數(shù)據(jù)后父進(jìn)程殺死子進(jìn)程,父進(jìn)程回收子進(jìn)程,然后父進(jìn)程退出,最后銷毀消息隊(duì)列

刪除消息隊(duì)列也可以直接使用命令 ipcrm -q 7

到此這篇關(guān)于php消息隊(duì)列實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)php消息隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • PHP實(shí)現(xiàn)普通hash分布式算法簡(jiǎn)單示例

    PHP實(shí)現(xiàn)普通hash分布式算法簡(jiǎn)單示例

    這篇文章主要介紹了PHP實(shí)現(xiàn)普通hash分布式算法,結(jié)合實(shí)例形式分析了普通hash分布式算法類的定義與簡(jiǎn)單使用技巧,需要的朋友可以參考下
    2018-08-08
  • PHP獲取類私有屬性的3種方法

    PHP獲取類私有屬性的3種方法

    這篇文章主要介紹了PHP獲取類私有屬性的3種方法,幫助大家更好的理解和使用php,感興趣的朋友可以了解下
    2020-09-09
  • PHP簡(jiǎn)單實(shí)現(xiàn)防止SQL注入的方法

    PHP簡(jiǎn)單實(shí)現(xiàn)防止SQL注入的方法

    這篇文章主要介紹了PHP簡(jiǎn)單實(shí)現(xiàn)防止SQL注入的方法,結(jié)合實(shí)例形式分析了php防止SQL注入的常用操作技巧與注意事項(xiàng),代碼備有詳盡注釋便于理解,需要的朋友可以參考下
    2018-03-03
  • 如何從防護(hù)角度看Thinkphp歷史漏洞

    如何從防護(hù)角度看Thinkphp歷史漏洞

    19年初,網(wǎng)上公開了2個(gè)Thinkphp5的RCE漏洞,漏洞非常好用,導(dǎo)致有很多攻擊者用掃描器進(jìn)行全網(wǎng)掃描。我們通過ips設(shè)備持續(xù)觀察到大量利用這幾個(gè)漏洞進(jìn)行批量getshell的攻擊流量,本文主要從流量角度簡(jiǎn)要分析和利用thinkphp進(jìn)行攻擊的全網(wǎng)掃描和getshell流量痕跡。
    2021-05-05
  • PHP類繼承 extends使用介紹

    PHP類繼承 extends使用介紹

    我們?cè)谖恼轮袨榇蠹以敿?xì)介紹了有關(guān)PHP類繼承 extends的實(shí)現(xiàn)方法,希望對(duì)于新手來說能夠提升他們?cè)赑HP語言編程中的能力
    2014-01-01
  • PHP數(shù)組的內(nèi)部實(shí)現(xiàn)你了解嗎

    PHP數(shù)組的內(nèi)部實(shí)現(xiàn)你了解嗎

    這篇文章主要為大家詳細(xì)介紹了PHP數(shù)組的內(nèi)部實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 遍歷指定目錄下的所有目錄和文件的php代碼

    遍歷指定目錄下的所有目錄和文件的php代碼

    遍歷指定目錄下的所有目錄和文件的php代碼,需要的朋友可以參考下。
    2011-11-11
  • PHP無法訪問遠(yuǎn)程mysql的問題分析及解決

    PHP無法訪問遠(yuǎn)程mysql的問題分析及解決

    首先說明,遠(yuǎn)程服務(wù)器是可遠(yuǎn)程訪問的,經(jīng)過一番折騰最后想到了SELINUX的問題,對(duì)比了下AB兩臺(tái)機(jī)器,果然設(shè)置不一樣!估計(jì)就是它的問題
    2013-05-05
  • PHP的5個(gè)安全措施小結(jié)

    PHP的5個(gè)安全措施小結(jié)

    多年來,PHP一直是一個(gè)穩(wěn)定的、廉價(jià)的運(yùn)行基于web應(yīng)用程序的平臺(tái)。像大多數(shù)基于web的平臺(tái)一樣,PHP也是容易受到外部攻擊的
    2012-07-07
  • PHP詳細(xì)徹底學(xué)習(xí)Smarty

    PHP詳細(xì)徹底學(xué)習(xí)Smarty

    Smarty是一個(gè)php模板引擎,它分開了邏輯程序和外在的內(nèi)容,提供了一種易于管理的方法. Smarty要求web服務(wù)器運(yùn)行php4.0.6和以上版本. smarty安裝需要smarty庫文件??梢匀ス俜骄W(wǎng)站http://smarty.php.net下載。 網(wǎng)上講了很多安裝的教程,但是我都沒有成功,所以直接把整個(gè)目錄名改為smarty直接復(fù)制到了網(wǎng)站所在的目錄下,然后打開http://網(wǎng)站路徑/smarty/demo/index.php,顯示正常,應(yīng)該算是安裝成功了。
    2008-03-03

最新評(píng)論

三明市| 韩城市| 保山市| 姚安县| 丰城市| 乡宁县| 弥勒县| 连平县| 湟源县| 桓台县| 汶川县| 竹溪县| 临沂市| 化德县| 田东县| 榆社县| 绩溪县| 古交市| 营山县| 和政县| 五常市| 社旗县| 射洪县| 吐鲁番市| 渭南市| 仲巴县| 尼勒克县| 桂阳县| 澄城县| 浦江县| 黄骅市| 手机| 资源县| 辛集市| 宜城市| 阳山县| 准格尔旗| 阿勒泰市| 淮阳县| 崇礼县| 洞头县|