国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > PHP > 正文

PHP網絡編程 之Accept 阻塞模型的介紹

2020-03-22 19:15:07
字體:
來源:轉載
供稿:網友
本篇文章給大家分享的內容是關于PHP網絡編程 之Accept 阻塞模型的介紹,內容很詳細,有需要的朋友可以參考一下,希望可以幫助到大家。

Accept 阻塞模型是一種相對古老的模型,不過里面蘊含了許多有趣的知識,比如阻塞/非阻塞、鎖、超時重傳...

服務端程序 acceptSever.php
 ?php
$socket = stream_socket_server( tcp://0.0.0.0:{$port} , $errno, $errstr); if (!$socket) die( $errstr ($errno)
while ($conn = stream_socket_accept($socket, -1)) { // 這樣設置不超時才有用 html' target='_blank'>static $id = 0; # 進程 id static $ct = 0; # 接收數據的長度 $ct_last = $ct; $ct_data = # 接受的數據 $buffer = # 分段讀取數據 $id++; echo Client $id come . PHP_EOL; # 持續監聽 while (!preg_match( {/r/n} , $buffer)) { // 沒有讀到結束符,繼續讀// if (feof($conn)) break; // 防止 popen 和 fread 的 bug 導致的死循環 $buffer = fread($conn, 1024); echo R . PHP_EOL; # 打印讀的次數 $ct += strlen($buffer); $ct_data .= preg_replace( {/r/n} , , $buffer); $ct_size = ($ct - $ct_last) * 8; echo [$id] . __METHOD__ . . $ct_data . PHP_EOL; fwrite($conn, Received $ct_size byte data./r/n fclose($conn); fclose($socket);new SocketServer(2000);
客戶端程序 acceptClient.php
 ?php# 日志記錄function debug ($msg) error_log($msg, 3, ./socket.log if ($argv[1]) { $socket_client = stream_socket_client( tcp://0.0.0.0:2000 , $errno, $errstr, 30); /* 設置腳本為非阻塞 */# stream_set_blocking($socket_client, 0); /* 設置腳本超時時間 */# stream_set_timeout($socket_client, 0, 100000); if (!$socket_client) { die( $errstr ($errno)  } else { # 填充容器 $msg = trim($argv[1]); for ($i = 0; $i $i++) { $res = fwrite($socket_client, $msg($i)  usleep(100000); echo W // 打印寫的次數# debug(fread($socket_client, 1024)); // 將產生死鎖,因為 fread 在阻塞模式下未讀到數據時將等待 fwrite($socket_client, /r/n // 傳輸結束符 # 記錄日志 debug(fread($socket_client, 1024)); fclose($socket_client);else {// $phArr = array();// for ($i = 0; $i $i++) {// $phArr[$i] = popen( php .__FILE__. {$i}:test , r // foreach ($phArr as $ph) {// pclose($ph); for ($i = 0; $i $i++) { system( php .__FILE__. {$i}:test # 這里等于 php 當前文件 腳本參數 }
代碼解析

首先,解釋一下以上的代碼邏輯:客戶端 acceptClient.php 循環發送數據,最后發送結束符;服務端 accept Server.php 使用 accept 阻塞方式接收 socket 連接,然后循環接收數據,直到收到結束符,返回結果數據(接收到的字節數)客戶端收到服務器返回的數據,寫入日志。雖然邏輯很簡單,但是其中有幾種情況很值得分析一下:

A 默認情況下,運行 php socket_client.php test,客戶端打出 10 個 W,服務端打出若干個 R 后面是接收到的數據,socket.log 記錄下服務端返回的接收結果數據,效果如下:
1500280071-5b5b18674c9ed_articlex.png
這種情況很容易理解,不再贅述。然后,使用 telnet 命令同時打開多個客戶端,你會發現服務器一個時間只處理一個客戶端,如圖所示:
3477710993-5b5b1a8e66d59_articlex.png
其他需要在后面“排隊”;這就是阻塞 IO 的特點,這種模式的弱點很明顯,效率極低。

B 只打開 socket_client.php 第 29 行的注釋代碼,再次運行 php socket_client.php test 客戶端打出一個 W,服務端也打出一個 R,之后兩個程序都卡住了。這是為什么呢,分析邏輯后你會發現,這是由于客戶端在未發送結束符之前就向服務端要返回數據;而服務端由于未收到結束符,也在向客戶端要結束符,造成死鎖。而之所以只打出一個 W 和 R,是因為 fread 默認是阻塞的。要解決這個死鎖,必須打開 socket_client.php 第 17 行的注釋代碼,給 socket 設置一個 0.1 秒的超時,再次運行你會發現隔 0.1 秒出現一個 W 和 R 之后正常結束,服務端返回的接收結果數據也正常記錄了。可見 fread 缺省是阻塞的,我們在編程的時候要特別注意,如果沒有設置超時,就很容易會出現死鎖。

C 只打開 14 行注釋設置腳本為非阻塞,運行 php socket_client.php test,結果基本和情況 A 相同,唯一不同的是 socket.log 沒有記錄下返回數據,這是因為當我們非阻塞下客戶端不必等待接收到服務器的響應結果就可以繼續往下執行,當執行到 debug 的時候,讀取的數據還是空的,所以 socket.log 也是空的。這里可以看出客戶端運行在阻塞和非阻塞模式的區別,當然在客戶端不在乎接受結果的情況下,可以使用非阻塞模式來獲得最大效率。

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 广东省| 绥中县| 凉山| 秦皇岛市| 乌兰察布市| 鄂尔多斯市| 丰镇市| 和硕县| 体育| 涡阳县| 红原县| 抚顺县| 枣阳市| 达州市| 黎川县| 神农架林区| 宣威市| 随州市| 三明市| 彭阳县| 浦县| 南昌市| 顺义区| 丹江口市| 寿阳县| 赤水市| 迁西县| 徐闻县| 开平市| 全南县| 冕宁县| 淮阳县| 连州市| 乌鲁木齐县| 惠东县| 论坛| 正宁县| 郧西县| 西吉县| 阿合奇县| 仙游县|