摘要:目前的常用的復(fù)用模型有三種,,。如果設(shè)置為,則將一直阻塞到有套接字滿足條件。模型是和的增強(qiáng)版,同一樣,文件描述符數(shù)量無限制。支持多種多路復(fù)用技術(shù),和等。同時為文件描述符信號超時設(shè)定等事件提供了監(jiān)聽回調(diào)。
“ 閱讀本文大概需要 6 分鐘?!?/p>
我們之前采用的多進(jìn)程方式實現(xiàn)的服務(wù)器端,一次創(chuàng)建多個工作子進(jìn)程來給客戶端提供服務(wù)。其實這種方式是存在問題的。
可以打個比方:如果我們先前創(chuàng)建的幾個進(jìn)程承載不了目前快速發(fā)展的業(yè)務(wù)的話,是不是還得增加進(jìn)程數(shù)?我們都知道系統(tǒng)創(chuàng)建進(jìn)程是需要消耗大量資源的,所以這樣就會導(dǎo)致系統(tǒng)資源不足的情況。
那么有沒有一種方式可以讓一個進(jìn)程同時為多個客戶端端提供服務(wù)?
接下來要講的IO復(fù)用技術(shù)就是對于上述問題的最好解答。
對于IO復(fù)用,我們可以通過一個例子來很好的理解它。(例子來自于《TCP/IP網(wǎng)絡(luò)編程》)
某教室有10名學(xué)生和1名老師,這些學(xué)生上課會不停的提問,所以一個老師處理不了這么多的問題。那么學(xué)校為每個學(xué)生都配一名老師,
也就是這個教室目前有10名老師。此后,只要有新的轉(zhuǎn)校生,那么就會為這個學(xué)生專門分配一個老師,因為轉(zhuǎn)校生也喜歡提問題。如果把以上例子中的學(xué)生比作客戶端,那么老師就是負(fù)責(zé)進(jìn)行數(shù)據(jù)交換的服務(wù)端。則該例子可以比作是多進(jìn)程的方式。
后來有一天,來了一位具有超能力的老師,這位老師回答問題非常迅速,并且可以應(yīng)對所有的問題。而這位老師采用的方式是學(xué)生提問前必須先舉手,確認(rèn)舉手學(xué)生后在回答問題。則現(xiàn)在的情況就是IO復(fù)用。
目前的常用的IO復(fù)用模型有三種:select,poll,epoll。
select模型:
說的通俗一點就是各個客戶端連接的文件描述符也就是套接字,都被放到了一個集合中,調(diào)用select函數(shù)之后會一直監(jiān)視這些文件描述符中有哪些可讀,如果有可讀的描述符那么我們的工作進(jìn)程就去讀取資源。PHP 中有內(nèi)置的函數(shù)來完成 select 系統(tǒng)調(diào)用。
函數(shù)原型:
int socket_select (array &$read ,array &$write ,array &$except ,int $tv_sec [,int $tv_usec= 0 ])
作用說明:用于確定一個或多個套接字的狀態(tài),對每一個套接字,調(diào)用者可查詢它的可讀性、可寫性及錯誤狀態(tài)信息
參數(shù)說明:
read: 指向一組等待可讀性檢查的套接字
write: 指向一組等待可寫性檢查的套接字
except: 指向一組等待錯誤檢查的套接字
tv_sec: 用來設(shè)置 select() 的等待時間,秒
tv_usec: 用來設(shè)置 select() 的等待時間,微妙
這里注意一下,如果 tv_sec 設(shè)置為0,則 socket_select 立即返回,也就是非阻塞的。如果 tv_sec 設(shè)置為 null ,則 socket_select 將一直阻塞到有套接字滿足條件。
下面通過代碼代碼來簡單舉例:
poll模型:
poll 和 select 的實現(xiàn)非常類似,本質(zhì)上的區(qū)別就是存放 fd 集合的數(shù)據(jù)結(jié)構(gòu)不一樣。select 在一個進(jìn)程內(nèi)可以維持最多 1024 個連接,poll 在此基礎(chǔ)上做了加強(qiáng),可以維持任意數(shù)量的連接。
但 select 和 poll 方式有一個很大的問題就是,我們不難看出來 select 是通過輪訓(xùn)的方式來查找是否可讀或者可寫,打個比方,如果同時有100萬個連接都沒有斷開,而只有一個客戶端發(fā)送了數(shù)據(jù),所以這里它還是需要循環(huán)這么多次,造成資源浪費。
所以后來出現(xiàn)了 epoll 系統(tǒng)調(diào)用。
epoll模型:
epoll 是 select 和 poll 的增強(qiáng)版,epoll 同 poll 一樣,文件描述符數(shù)量無限制。
epoll是基于內(nèi)核的反射機(jī)制,在有活躍的 socket 時,系統(tǒng)會調(diào)用我們提前設(shè)置的回調(diào)函數(shù)。而 poll 和 select 都是遍歷。
但是也并不是所有情況下 epoll 都比 select/poll 好,比如在如下場景:
在大多數(shù)客戶端都很活躍的情況下,系統(tǒng)會把所有的回調(diào)函數(shù)都喚醒,所以會導(dǎo)致負(fù)載較高。既然要處理這么多的連接,那倒不如 select 遍歷簡單有效。
在 PHP 中我們可以使用 libevet 拓展來實現(xiàn) epoll。
libevent 是一個用C語言寫的,基于事件驅(qū)動的高性能網(wǎng)絡(luò)庫。支持多種 I/O 多路復(fù)用技術(shù),epoll、 poll、 dev/poll、 select 和 kqueue 等。 libevent 同時為文件描述符、信號、超時設(shè)定等事件提供了監(jiān)聽回調(diào)。所以這種編程方式也可以說是事件編程。
先放代碼體驗一番:
服務(wù)端:
客戶端:
先說簡單的客戶端,客戶端的主要作用也就是像服務(wù)端發(fā)送了兩句話。第一句是 hello world!,然后等待兩秒之后再次發(fā)送 send again!
并且每次發(fā)送之后都將接收到服務(wù)端返回的字節(jié)數(shù)。
講解服務(wù)端之前先了解一下關(guān)于時間循環(huán)的一些函數(shù):
event_base_new 創(chuàng)建一個事件庫(只需創(chuàng)建一次)
event_new 創(chuàng)建事件
event_set 為創(chuàng)建的事件設(shè)置要監(jiān)聽文件描述符fd,以及事件類型、回調(diào)函數(shù)
event_base_set 將創(chuàng)建的事件與事件庫關(guān)聯(lián)
event_add 將設(shè)置好的事件加入事件監(jiān)聽器
event_base_loop 開啟事件循環(huán)
還有 event_set 的幾個參數(shù):
EV_TIMEOUT: 超時
EV_READ: 只要網(wǎng)絡(luò)緩沖中還有數(shù)據(jù),回調(diào)函數(shù)就會被觸發(fā)
EV_WRITE: 只要塞給網(wǎng)絡(luò)緩沖的數(shù)據(jù)被寫完,回調(diào)函數(shù)就會被觸發(fā)
EV_SIGNAL: POSIX信號量
EV_PERSIST: 不指定這個屬性的話,回調(diào)函數(shù)被觸發(fā)后事件會被刪除
服務(wù)端的三個函數(shù):
read_cb() 接受數(shù)據(jù),發(fā)送數(shù)據(jù)
error_cb() 錯誤處理
accept_cb() 受理請求并且把新的文件描述符加入事件庫,同時注冊 read_cb 回調(diào)
整個服務(wù)端的主要流程如下:
1.創(chuàng)建事件庫
2.設(shè)置事件回調(diào)
3.綁定事件
4.開始事件循環(huán)
5.如有符合條件的文件描述符則系統(tǒng)開始調(diào)用我們提前設(shè)定好的處理函數(shù)
至于詳細(xì)的流程我就不分析了,大致流程應(yīng)該都能理解,接下來就靠自己鞏固了。一定要自己動手實踐才行。
當(dāng)然本文也只是起到拋磚引玉而已,以上有問題的地方歡迎指出。由于作者沒有開通留言功能,所以歡迎后臺直接回復(fù)哦。( 阿毛的Coding之路 )
本人會持續(xù)分享一些關(guān)于編程以及編程自學(xué)相關(guān)的文章(不限于PHP),記錄自己的自學(xué)編程之路。同時希望自己的分享能夠幫助一些對編程感興趣以及正在編程道路上的朋友。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/30891.html
摘要:前面幾講手撕了網(wǎng)關(guān)服務(wù)器回顯服務(wù)器服務(wù)的代碼,但是這幾個一次只能監(jiān)聽一個文件描述符,因此性能非常原始低下。復(fù)用能使服務(wù)器同時監(jiān)聽多個文件描述符,是服務(wù)器性能提升的關(guān)鍵。表示要操作的文件描述符,指定操作類型,指定事件。 ?本系列文章導(dǎo)航: 手把手寫C++服務(wù)器(0):專欄文章-匯總導(dǎo)航【更...
摘要:基本概念多路復(fù)用是指內(nèi)核一旦發(fā)現(xiàn)進(jìn)程指定的一個或者多個條件準(zhǔn)備讀取它就通知該進(jìn)程多路復(fù)用適用如下場合當(dāng)客戶處理多個描述字時一般是交互式輸入和網(wǎng)絡(luò)套接口必須使用復(fù)用當(dāng)一個客戶同時處理多個套接口時而這種情況是可能的但很少出現(xiàn)如果一個服務(wù)器既要處 基本概念 IO多路復(fù)用是指內(nèi)核一旦發(fā)現(xiàn)進(jìn)程指定的一個或者多個IO條件準(zhǔn)備讀取, 它就通知該進(jìn)程. IO多路復(fù)用適用如下場合: ?。?)當(dāng)客...
閱讀 2791·2021-11-22 14:45
閱讀 936·2021-10-15 09:41
閱讀 1098·2021-09-27 13:35
閱讀 3767·2021-09-09 11:56
閱讀 2659·2019-08-30 13:03
閱讀 3224·2019-08-29 16:32
閱讀 3332·2019-08-26 13:49
閱讀 806·2019-08-26 10:35