一. 基礎知識
1.1 Swoole
Swoole是面向生產環境的php非同步網路通訊引擎, php開發人員可以利用Swoole開發出高效能的server服務。Swoole的server部分, 內容很多, 也涉及很多的知識點, 本文僅對其server進行簡單的概述, 具體的實現細節在後續的文章中再進行詳細介紹。
推薦(免費):
1.2 網路程式設計
1. 網路通訊是指在一臺(或者多臺)機器上啟動一個(或者多個)程序, 監聽一個(或者多個)埠, 按照某種協定(可以是標準協定http, dns; 也可以是自行定義的協定)與使用者端交換資訊。
2. 目前的網路程式設計多是在tcp, udp或者更上層的協定之上進行程式設計。Swoole的server部分是基於tcp以及udp協定的。
3. 利用udp進行程式設計較為簡單, 本文主要介紹tcp協定之上的網路程式設計
4. TCP網路程式設計主要涉及4種事件
● 連線建立: 主要是指使用者端發起連線(connect)以及伺服器端接受連線(accept)
● 訊息到達: 伺服器端接受到使用者端傳送的資料,該事件是TCP網路程式設計最重要的事件,伺服器端對於該類事件進行處理時, 可以採用阻塞式或者非阻塞式,除此之外, 伺服器端還需要考慮分包, 應用層緩衝區等問題
● 訊息傳送成功: 傳送成功是指應用層將資料成功傳送到核心的通訊端傳送緩衝區中,並不是指使用者端成功接受資料。對於低流量的服務而言,資料通常一次性即可傳送完,並不需要關心此類事件。如果一次性不能將全部資料傳送到核心緩衝區,則需要關心訊息是否成功傳送(阻塞式程式設計在系統呼叫(write, writev, send等)返回後即是傳送成功, 非阻塞式程式設計則需要考慮實際寫入的資料是否與預期一致)
● 連線斷開: 需要考慮使用者端斷開連線(read返回0)以及伺服器端斷開連線(close, shutdown)
5. tcp建立連線的過程如下圖
● 圖中, ACK、SYN表示標誌位, seq、ack為tcp包的序號以及確認序號
6. tcp斷開連線的過程如下圖
● 上圖考慮的是使用者端主動斷開連線的情況, 伺服器端主動斷開連線也類似
● 圖中, FIN、ACK表示標誌位, seq、ack為tcp包的序號以及確認序號
1.3 程序間通訊
1. 程序之間的通訊有無名管道(pipe), 有名管道(fifo), 訊號(signal), 號誌(semaphore), 通訊端(socket), 共用記憶體(shared memory)等方式
2. Swoole中採用unix域通訊端(通訊端的一種)用於多程序之間的通訊(指Swoole內部程序之間)
1.4 socketpair
1. socketpair用於建立一個通訊端對, 類似於pipe, 不同的是pipe是單向通訊, 雙向通訊需要建立兩次, socketpair呼叫一次即可實現雙向通訊, 除此之外, 由於使用的是通訊端, 還可以定義資料交換的方式
2. socketpair系統呼叫
1.5 守護行程(daemon)
1. 守護行程是一種特殊的後臺程序, 它脫離於終端, 用於週期性的執行某種任務
2. 行程群組
3. 對談
4. 建立守護行程的方式
1.6 Swoole tcp server範例
二. Swoole server
2.1 base模式
1. 說明
2. 啟動過程
2.2 process模式
1. 說明
2. 啟動過程
主程序pthread_create出react執行緒, 主執行緒和react執行緒各自進入自己的事件迴圈, reactor執行緒執行static int swRea-torThread_loop (swThreadParam *param), 等待處理事件
3. 結構圖
上圖並沒有考慮task_worker程序, 在預設情況下, task_worker程序數為0
三. 請求處理流程(process模式)
3.1 reactor執行緒與worker程序之間的通訊
1. Swoole master程序與worker程序之間的通訊如下圖所示
2. 假設reactor執行緒有2個, worker程序有3個, 則reactor與worker之間的通訊如下圖所示
3. reactor執行緒與worker程序通訊的封包
3.2 請求處理
1. master程序中的主執行緒負責監聽埠(listen
), 接受連線(accept
, 產生一個fd), 接受連線後將請求分配給reactor執行緒, 預設通過fd % reactor_number進行分配, 之後通過epoll_ctl
將fd加入到對應reactor執行緒中, 剛加入時監聽寫事件, 因為新接受連線建立的通訊端寫緩衝區為空, 故而一定可寫, 會被立刻觸發, 進而reactor執行緒進行一些初始化操作
epoll_create
建立)的情況epoll_ctl
是執行緒安全的(對應一個epollfd), 一個執行緒正在執行, 其他執行緒會被阻塞(因為需要同時操作epoll底層的紅黑樹)epoll_wait
也是執行緒安全的, 但是一個事件可能會被多個執行緒同時接收到, 實際中不建議多個執行緒同時epoll_wait
一個epollfd。Swoole中也是不存在這種情況的, Swoole中每個reactor執行緒都有自己的epollfdepoll_wait
, 一個執行緒呼叫epoll_ctl
, 根據man手冊, 如果epoll_ctl
新加入的fd已經準備好, 會使得執行epoll_wait
的執行緒變成非阻塞狀態(可以通過man epoll_wait
檢視相關內容)2. reactor執行緒中fd的寫事件被觸發, reactor執行緒負責處理, 發現是首次加入, 沒有資料可寫, 則會開啟讀事件監聽, 準備接受使用者端傳送的資料
3. reactor執行緒讀取到使用者的請求資料, 一個請求的資料接收完後, 將資料轉發給worker程序, 預設是通過fd % worker_number進行分配
4. worker程序收到reactor傳送的封包後, 進行處理, 處理完成後, 將請求結果傳送給主程序
5. 主程序收到worker程序傳送的封包, 這個會觸發某個reactor執行緒進行處理
6. reactor執行緒處理worker程序傳送的請求處理結果, 如果是直接傳送資料給使用者端, 則可以直接傳送, 如果需要改變這個這個連線的監聽狀態(例如close
), 則需要先找到監聽這個連線的reactor執行緒, 進而改變這個連線的監聽狀態(通過呼叫epoll_ctl
)
四. gdb偵錯
4.1 process模式啟動
4.2 base模式啟動
五. 總結及思考
1. 本文主要介紹了Swoole server的兩種模式: base模式、process模式, 詳細講解了兩種模式的網路程式設計模型, 並重點介紹了process模式下, 程序間通訊的方式、請求的處理流程等
2. process模式下, 為什麼不直接在主程序中建立多個執行緒, 由執行緒直接進行處理請求(可以避免程序間通訊的開銷), 而是建立出manager程序, 再由manager程序建立出worker程序, 由worker程序處理請求?
3. process模式下, 主程序中的每個reactor執行緒都可以同時處理多個請求, 多個請求是並行處理的, 我們從2個維度看
4. 使用Swoole建立tcp server時, 由於tcp是位元組流的協定, 需要分包, 而Swoole在不清楚使用者端與伺服器端通訊協定的情況下, 無法進行分包, process模式下, reactor交給worker程序的資料也只能是位元組流的, 需要使用者自行處理。當然, 一般情況也不需要自行構建協定, 使用tcp server, Swoole已經支援Http, Https等協定
以上就是淺析Swoole server的詳細內容,更多請關注TW511.COM其它相關文章!