摘要:有研究過框架的同學就會發現,其實最核心的,就是用了拓展加上拓展來實現其底層的網絡服務和多進程調度。我們在模式下,測試起五個進程主進程要等待回收我們,這樣就很簡單的實現了一個多進程的協程服務。
有研究過Workman框架的同學就會發現,其實workman最核心的,就是用了php socket拓展加上pcntl拓展來實現其底層的網絡服務和多進程調度。那我們今天就來探討如何使用Swoole的CoroutineSocket模塊來實現自己的tcp服務。
我們先編寫一段小的測試代碼,test.php 代碼如下
$socket = new CoSocket(AF_INET, SOCK_STREAM, 0); $socket->bind("127.0.0.1", 9601); $socket->listen(128); go(function () use ($socket) { while(true) { $client = $socket->accept(-1); $data = $client->recv(64,10); var_dump("Recv:".$data); $client->sendAll("reply at ".time()); $client->close(); } });
我們執行
php test.php
并新建一個cmd控制臺,用telnet模擬tcp客戶端,可以看到如下結果:
telnet 127.0.0.1 9601 Trying 127.0.0.1... Connected to localhost. Escape character is "^]". asd reply at 1559713416 Connection closed by foreign host
以上說明我們已經成功建立了一個簡單的TCP服務器。而有細心的同學就會發現,以上代碼如果我在recv后,有一些數據庫行為發生,那我該TCP服務器在同一時間就僅僅只能accept鏈接并處理一個鏈接的事情,并發能力接近于1。因此我們可以做一點小小的改進,如下:
$socket = new CoSocket(AF_INET, SOCK_STREAM, 0); $socket->bind("127.0.0.1", 9601); $socket->listen(128); go(function () use ($socket) { while(true) { $client = $socket->accept(-1); go(function () use ($client){ $data = $client->recv(64,10); var_dump("Recv:".$data); //模擬數據庫耗時,假定我們的數據庫也是用協程api co::sleep(1); $client->sendAll("reply at ".time()); $client->close(); }); } });
我們利用協程,把連接accept后的邏輯,全部放到另外一個子協程當中處理,讓我們的TCP服務器可以繼續accept連接,也就提高了我們的并發能力。然而,在實際的編程中,我們不可能做到完全的百分百協程API,而且我的機器也是多核心的處理器,那么此刻我如何盡可能的利用我的CPU呢?因此我們可以利用端口復用的特性和Swoole的Process來構建一個多進程TCP協程服務器。
引入Process因為在本章節中,對Swoole Process的封裝不是我們關心的,因此我們這里直接使用EasySwoole封裝好的進程組件。
composer require easyswoole/component
實現我的Process Class,代碼如下
use CoSocket; use EasySwooleComponentProcessAbstractProcess; class Server extends AbstractProcess { protected function run($arg) { $socket = new Socket(AF_INET, SOCK_STREAM, 0); //關鍵在這里,允許復用 $socket->setOption(SOL_SOCKET,SO_REUSEPORT,true); $socket->setOption(SOL_SOCKET,SO_REUSEADDR,true); $socket->bind("127.0.0.1", 9601); $socket->listen(128); go(function () use ($socket) { while(true) { $client = $socket->accept(-1); go(function () use ($client){ $data = $client->recv(64,10); var_dump("Recv:".$data); //模擬數據庫耗時,假定我們的數據庫也是用協程api co::sleep(1); $client->sendAll("reply at ".time()); $client->close(); }); } }); } }
我們在以上代碼中,加入了允許端口復用的選項,否則在多進程模式下,會導致監聽失敗。我們在cli模式下,測試起五個進程
for ($i = 1;$i < 5;$i++){ $p = new Server("TcpServer.{$i}"); $p->getProcess()->start(); } //主進程要等待回收 while($ret = SwooleProcess::wait()) { echo "PID={$ret["pid"]} "; }
我們,這樣就很簡單的實現了一個多進程的TCP協程服務。總而言之,Swoole 4.x的協程能力,還是很強大的,讓PHPer可以以最小的代價來實現一個高性能的TCP服務,而不是需要去學習新的一門語言,若需要更多的完善代碼,可以參考http://easyswoole.com/ 這個框架的項目代碼,如果有喜歡的同學,可以隨意點個 star ,github地址 https://github.com/easy-swool...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/31663.html
摘要:訪問安全問題為什么說有訪問安全問題呢傳統地,在的的環境中,很少有遇到所謂變量安全訪問問題。上下文管理器為了解決這個問題,我們引入協程上下文管理這樣的概念,由此來實現每個協程環境內的數據隔離。 訪問安全問題 為什么說有訪問安全問題呢?傳統地,在php的的環境中,很少有Phper遇到所謂變量安全訪問問題。舉個例子,代碼大約如下: class db { protected stati...
摘要:然而盡管如此,很多人可能都沒有思考過,如何優雅的寫出自己的物聯網服務器。 PHP不適合做物聯網服務端嗎? 在傳統的思維中,經常會有人告訴你,php不適合用來做物聯網服務端,讓你換java,node,go等其他語言,是的,沒錯傳統意義上的php,確實很難做物聯網服務器,因為它實在太蹩腳了,當然,這也不是意味著徹底就不能做。舉個例子,當你想實現一個TCP服務器的時候,你可能需要寫出原理大約...
摘要:協程與信箱得益于,我們可以基于的協程與快速實現一個信箱模式調度。樣例代碼比如在一個聊天室中,我們可以定義一個房間模型。 什么是Actor? Actor對于PHPer來說,可能會比較陌生,寫過Java的同學會比較熟悉,Java一直都有線程的概念(雖然PHP有Pthread,但不普及),它是一種非共享內存的并發模型,每個Actor內的數據獨立存在,Actor之間通過消息傳遞的形式進行交互調...
摘要:年月日,在上海舉行的第六屆中國開發者大會上,騰訊開源項目首次全面發布版本,閱文集團高級開發工程師梁晨對如何通過構建高性能框架做了經驗分享。分享內容作為騰訊開源的框架,在發布之后即受到開源領域的關注。閱文集團本身也有一塊新的業務在使用。 2018年5月19日,在上海舉行的第六屆中國PHP開發者大會(PHPCon)上,騰訊開源項目TARS首次全面發布PHP版本,閱文集團高級開發工程師梁晨對...
摘要:協程完全有用戶態程序控制,所以也被成為用戶態的線程。目前支持協程的語言有很多,例如等。協程之旅前篇結束,下一篇文章我們將深入分析原生協程部分的實現。 寫在最前 ??Swoole協程經歷了幾個里程碑,我們需要在前進的道路上不斷總結與回顧自己的發展歷程,正所謂溫故而知新,本系列文章將分為協程之旅前、中、后三篇。 前篇主要介紹協程的概念和Swoole幾個版本協程實現的主要方案技術; 中篇主...
閱讀 1342·2021-09-24 10:26
閱讀 3655·2021-09-06 15:02
閱讀 604·2019-08-30 14:18
閱讀 576·2019-08-30 12:44
閱讀 3119·2019-08-30 10:48
閱讀 1936·2019-08-29 13:09
閱讀 1993·2019-08-29 11:30
閱讀 2279·2019-08-26 13:36