用PHP實現高併發伺服器

2021-10-23 19:42:32 字數 3113 閱讀 1870

一提到高併發,就沒有辦法繞開i/o復用,再具體到特定的平台linux, 就沒辦法繞開epoll. epoll為啥高效的原理就不講了,感興趣的同學可以自行搜尋研究一下,也可以直接用現成的swoole,原理一樣都挺不錯的。

php怎麼玩epoll?首先得安裝個libevent庫,再裝個event擴充套件或者libevent擴充套件就可以愉快地玩耍了.

有些人搞不清楚libevent庫跟libevent擴充套件的區別,簡單來說,libevent庫是c語言對epoll的封裝,跟php毛關係都沒有;

libevent擴充套件就是php跟libevent庫的溝通橋梁。實際上php的很多擴充套件就是幹這個事的,有一些優秀的c語言庫,php想直接拿來用,就通過php擴充套件的方式接入到php。

libevent擴充套件和event擴充套件隨便選乙個裝,event擴充套件因為更物件導向一點。自己去裡面搜跟自己php版本對應的擴充套件,下好編譯安裝一下就ok了.電腦裝了多個版本的php編譯的時候注意一下,phpize的版本要對應上,別搞錯了,典型的五步曲:

phpize

./configure

make

make install

php -m | grep event #看看裝上了沒

我們要實現的伺服器,傳輸層是tcp協議,應用層協議太多太複雜,限於篇幅,會簡單地以http伺服器舉個例子,http協議本身就很複雜,要實現起來細節上有很多考究,我們也不會完全實現http協議。

首先,建立乙個socket,三步曲,socket_create、socket_bind、socket_listen,為什麼是這三步曲呢?

很簡單,不管你傳輸層協議是啥,你下面的網路層協議你得選個版本吧,ipv4還是ipv6,傳輸層工作方式你得選乙個吧,全雙工、半雙工還是單工,tcp還是udp你也得選乙個吧,socket_create就是這三個選項;

確定了網路層和傳輸層,你得告訴我監聽哪個埠吧,這就對應了socket_bind;然後你得開啟監聽,並指定乙個客戶端的佇列長度吧,這就是socket_listen幹的事。

建立完了,同步阻塞咱就不介紹了,乙個程序同時最多hold處乙個連線,多幾個連線同時請求,就得等唄,超過了socket_listen指定的佇列長度,就得返回504了。多程序也一樣,幾個程序就有幾個併發,程序又是昂貴資源,而且程序的上下文切換費時費力,導致整個系統效率低下。

沒關係,咱有epoll,hold住萬千請求不是夢,先實現乙個reactor。libevent庫就是reactor模式,直接呼叫函式就是在使用reactor模式,所以無需糾結到底php怎麼實現reactor模式。

<?php

use event;

use eventbase;

class reactor

return self::$instance;

}public function add($fd, $what, $cb, $arg = null)

$event->add();

$this->events[(int) $fd][$what] = $event;

}public function del($fd, $what = 'all')

} else

$events[$what]->free();}}

public function run()

public function stop()

}$this->reactor->stop();

}}

上面的**很簡單,簡單解釋一下概念,eventbase就是個容器,裡面裝的event例項,這麼一說,上面的**就非常好懂了。 然後乙個server.

<?php 

use throwable;

use monolog\handler\streamhandler;

class server

public function start()

);reactor::getinstance()->run();

}public function createtcpconnection()

return $socket;

}}

connection

<?php

class connection

public function handle()

private function read($conn)

}if ($this->read_buffer) else

}private function write($conn)

}}

先建立socket的三步曲,設定成非阻塞模式。然後把socket加到reactor中監聽可讀事件,可讀的意思就是,緩衝區有資料了,才可讀。可讀事件發生,說明有新連線來了,用 stream_socket_accept 接收新連線conn,把conn放到reactor中監聽可讀事件,可讀事件發生,說明客戶端有資料傳送過來了,迴圈讀直到沒資料,然後把conn放到reactor中監聽可寫事件,可寫事件發生,說明客戶端資料傳送完了,把協議組裝一下寫入響應。

應用層如果是http協議要注意一下connection: keep-alive頭,因為要復用連線,不要一寫完就關閉連線。

擼完收工,用 ab 測一下併發,加 -k 引數復用連線,i5+8g,3w的併發沒啥問題,當然我們這兒沒有磁碟i/o,實際情況要從磁碟讀取檔案,讀檔案要通過linux的系統呼叫,而且有幾次的檔案拷貝操作,花銷比較大,常用的解決思路是sendfile,零拷貝直接從乙個fd到另乙個fd,效率比較高,缺點就是php沒有現成的已經實現sendfile的擴充套件,得自己動手,開發成本有點高。

這就是php實現高併發伺服器的思路了,只要是用epoll解決的,思路都一樣,都是三步曲,放到reactor下監聽fd事件。當然這個只是最簡單的模型,還有很多可以改進的地方,比如說多程序,抄襲一下nginx,乙個主程序+n個工作程序,多程序的目的還是想利用多核並行工作。

c語言實現也是這樣,只是你可能不用libevent庫,自己封裝epoll,畢竟libevent庫有點重,你也用不到libevent的很多東西;當然了,c語言有一堆的資料結構以及定義在資料結構上的操作要寫,沒有gc,自己管理記憶體,還要有良好的設計,上多程序還得搞一搞ipc程序間通訊的東西,開發難度比php要大地多,開發周期也很長,有興趣的同學可以自己擼乙個玩。

Epoll實現伺服器高併發

最近在做乙個關於高併發伺服器相關的專案需要用到非同步 非阻塞io通訊,實現高tcp併發。以下用epoll技術實現乙個簡單的tcp高併發伺服器,驗證無業務處理的情況下,epoll處理併發連線的數的效果。include include include include include include in...

高併發計算伺服器數量

每秒查詢率qps 對乙個特定的查詢伺服器在規定時間內所處理流量多少的衡量標準,即每秒請求數,即最大談吐能力。併發數 併發數和qps是不同的概念,一般說qps會說多少併發使用者下qps,當qps相同時,併發使用者數越大,併發處理能力越好。當併發使用者數過大時,會造成程序 執行緒 頻繁切換,反正真正用於...

高併發伺服器(基於epoll)

本章節是用基本的linux unix基本函式編寫乙個完整的伺服器和客戶端例子,可在linux ubuntu 和unix freebsd 上執行,客戶端和服務端的功能如下 客戶端從標準輸入讀入一行,傳送到服務端 服務端從網路讀取一行,把小寫變為大寫,然後輸出到客戶端 客戶端收到服務端的響應,輸出這一行...