前面能夠說是弄了一系列的php socket和多進程的一大坨內容,知識淺顯、代碼粗暴、風格簡陋,總的說來,仍是差了一些細節。今天,就一些漏掉的細節補充一下。php
看代碼前,你要理解異步和非阻塞的區別是什麼,由於這兩者在表現結果上看起來是有點兒類似的,若是你沒搞明白,那麼必定要經過這個來理解一下《PHP socket初探 --- 關於IO的一些枯燥理論》。node
<?php // 建立一個監聽socket,這個一個阻塞IO的socket $listen = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); socket_bind( $listen, '0.0.0.0', 9999 ); socket_listen( $listen ); while( true ){ // socket_accept也是阻塞的,雖然有while,可是因爲accpet是阻塞的,因此這段代碼不會進入無限死循環中 $connect = socket_accept( $listen ); if( $connect ){ echo "有新的客戶端".PHP_EOL; } else { echo "客戶端鏈接失敗".PHP_EOL; } }
將上面代碼保存了運行一下,而後用telnet能夠鏈接上去。可是,這段代碼中有兩處是阻塞的,最主要就是監聽socket是阻塞的。那麼,非阻塞的監聽socket會是什麼感覺?git
<?php // 建立一個監聽socket,將其設置爲非阻塞 $listen = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); socket_bind( $listen, '0.0.0.0', 9999 ); socket_listen( $listen ); // ⚠️⚠️⚠️⚠️⚠️⚠️ 這裏設置非阻塞! socket_set_nonblock( $listen ); while( true ){ $connect = socket_accept( $listen ); if( $connect ){ echo "有新的客戶端".PHP_EOL; } else { echo "客戶端鏈接失敗".PHP_EOL; } }
將代碼保存了運行一下,告訴我:github
來來來,分析一波兒,爲啥會出現這種現象。由於監聽socket被設置成了非阻塞,咱們知道非阻塞就是程序立馬返回,而後再過段時間回來詢問,用例子就是「等饅頭過程當中,看下微博,擡頭問饅頭好了嗎?而後看下微信,擡頭問饅頭好了嗎?而後看下v2ex,擡頭問饅頭好了嗎?。。。 。。。」,這樣你是否是就能理解了?由於並無客戶端鏈接進來,因此每當詢問一次socket_accept後獲得的反饋都是「沒有鏈接」,因此就直接走到「客戶端鏈接失敗」的分支中去了,並且是不斷的不停的。這個時候,你用htop或者top命令查看服務器CPU,不出意外應該是100%,這是非阻塞的極大缺點。服務器
緊接着是異步呢?異步體如今哪兒了?咱們說異步,是你去阿梅那裏買饅頭,阿梅告訴你說「饅頭還沒好,你去幹別的吧,好了我打電話通知你」,而後你就專心去打遊戲去了,直到電話響了你去拿饅頭。Workerman的異步更可能是體如今對一個完整請求的處理流上,而不是正兒八經的異步的定義概念,若是你沒聽明白,那也可能正常,慢慢理解。最後,我補充一句:epoll是同步的,而不是異步。微信