推薦學習:
整個聊天室流程為:
- 使用者http介面登入獲得授權
- 通過授權請求http介面獲得好友列表,不同好友的最後一條未讀訊息以及未讀訊息數(用於首頁顯示)
- 通過授權請求獲得群列表(群訊息為了節省儲存空間沒有做已讀未讀)
- 建立ws連結
- 註冊斷線重連機制,當觸發close事件時,重連ws
- 建立ping定時器,每隔30秒進行一次ping
- 通過ws介面,獲得所有未讀訊息,使用者端進行處理,推播到通知欄等
- 接收新訊息推播,並顯示到訊息列表
- 當點選進某個群/好友訊息介面時,自動獲取最新n條訊息,使用者上拉時繼續獲取n條
cgi模式 通用閘道器介面(Common Gateway Interface),它允許web伺服器通過特定的協定與應用程式通訊, 呼叫原理大概為:
使用者請求->Web伺服器接收請求->fork子程序
呼叫程式/執行程式->程式返回內容/程式呼叫結束->web伺服器接收內容->返回給使用者
由於每次使用者請求,都得fork建立程序呼叫一次程式,然後銷燬程序,所以效能較低
fast-cgi是cgi模式的升級版,它像是一個常駐型的cgi,只要開啟後,就可一直處理請求,不再需要結束程序, 呼叫原理大概為:
web伺服器fast-cgi程序管理器初始化->預先fork n個程序
使用者請求->web伺服器接收請求->交給fast-cgi程序管理器->fast-cgi程序管理區接收,給其中一個空閒fast-cgi程序處理->處理完成,fast-cgi程序變為空閒狀態,等待下次請求->web伺服器接收內容->返回給使用者模組模式
apache+php執行時,預設使用的是模組模式,它把php作為apache的模組隨apache啟動而啟動,接收到使用者請求時則直接通過呼叫mod_php模組進行處理,詳細內容可自行百度
php-cli模式屬於命令列模式,對於很多剛開始學php就開始wamp,wnmp的開發者來說是最陌生的一種執行模式
該模式不需要藉助其他程式,直接輸入php xx.php 就能執行php程式碼
命令列模式和常規web模式明顯不一樣的是:
* 沒有超時時間
* 預設關閉buffer緩衝
* STDIN和STDOUT標準輸入/輸出/錯誤 的使用
* echo var_dump,phpinfo等輸出直接輸出到控制檯
* 可使用的類/函數 不同
* php.ini設定的不同
PHP-FPM(FastCGI 程序管理器)用於替換 PHP FastCGI 的大部分附加功能,對於高負載網站是非常有用的。
它的功能包括:
支援平滑停止/啟動的高階程序管理功能;
可以工作於不同的 uid/gid/chroot 環境下,並監聽不同的埠和使用不同的 php.ini 組態檔(可取代 safe_mode 的設定);
stdout 和 stderr 紀錄檔記錄;
在發生意外情況的時候能夠重新啟動並快取被破壞的 opcode;
檔案上傳優化支援;
"慢紀錄檔" - 記錄指令碼(不僅記錄檔名,還記錄 PHP backtrace 資訊,可以使用 ptrace或者類似工具讀取和分析遠端程序的執行資料)執行所導致的異常緩慢;
fastcgi_finish_request() - 特殊功能:用於在請求完成和重新整理資料後,繼續在後臺執行耗時的工作(錄入視訊轉換、統計處理等);
動態/靜態子程序產生;
基本 SAPI 執行狀態資訊(類似Apache的 mod_status);
基於 php.ini 的組態檔。
它的工作原理大概為:
php-fpm啟動->生成n個fast-cgi協定處理程序->監聽一個埠等待任務
使用者請求->web伺服器接收請求->請求轉發給php-fpm->php-fpm交給一個空閒程序處理
->程序處理完成->php-fpm返回給web伺服器->web伺服器接收資料->返回給使用者
網路協定為計算機網路中進行資料交換而建立的規則,標準或約定的集合,所有的計算機/手機等網路裝置通訊都得遵循網路協定.
網路協定根據通訊的步驟,層級劃分為7個層級,從上往下為:
應用層
表示層
對談層
傳輸層
網路層
資料鏈路層
物理層
ip協定是網際網路的基礎協定,它是目前最流行的一種網路協定
IP的責任就是把資料從源傳送到目的地。它不負責保證傳送可靠性,流控制,包順序和其它對於主機到主機協定來說很普通的服務。
這個協定由主機到主機協定呼叫,而此協定負責呼叫本地網路協定將封包傳送以下一個閘道器或目的主機。例如TCP可以呼叫IP協定,在呼叫時傳送目的地址和源地址作為引數,IP形成封包並呼叫本地網路(協定)介面傳送封包。
IP實現兩個基本功能:定址和分段。IP可以根據封包包頭中包括的目的地址將封包傳送到目的地址,在此過程中IP負責選擇傳送的道路,這種選擇道路稱為路由功能。如果有些網路內只能傳送小封包,IP可以將封包重新組裝並在報頭域內註明。IP模組中包括這些基本功能,這些模組存在於網路中的每臺主機和閘道器上,而且這些模組(特別在閘道器上)有路由選擇和其它服務功能。對IP來說,封包之間沒有什麼聯絡,對IP不好說什麼連線或邏輯鏈路。
IP使用四個關鍵技術提供服務:服務型別,生存時間,選項和報頭校驗碼。服務型別指希望得到的服務品質。服務型別是一個引數集,這些引數是Internet能夠提供服務的代表。這種服務型別由閘道器使用,用於在特定的網路,或是用於下下一個要經過的網路,或是下一個要對這個封包進行路由的閘道器上選擇實際的傳送引數。生存時間是封包可以生存的時間上限。它由傳送者設定,由經過路由的地方處理。如果未到達時生存時間為零,拋棄此封包。對於控制函數來說選項是重要的,但對於通常的通訊來說它沒有存在的必要。選項包括時間戳,安全和特殊路由。報頭校驗碼保證資料的正確傳輸。如果校驗出錯,拋棄整個封包。
把資料從源傳送到目的地時,需要有ip地址才能傳輸,現在ip地址分為ipv4和ipv6 兩種地址,現在最常見的就是ipv4地址,例如127.0.0.1(本機地址) 119.75.217.109(百度ip)
ip傳輸必須要有明確的ip地址,才能進行資料傳送
TCP(Transmission Control Protocol 傳輸控制協定)是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協定,由IETF的RFC 793定義。在簡化的計算機網路OSI模型中,它完成第四層傳輸層所指定的功能,使用者資料包協定(UDP)是同一層內 另一個重要的傳輸協定。在因特網協定族(Internet protocol suite)中,TCP層是位於IP層之上,應用層之下的中間層。不同主機的應用層之間經常需要可靠的、像管道一樣的連線,但是IP層不提供這樣的流機制,而是提供不可靠的包交換。
應用層向TCP層傳送用於網間傳輸的、用8位元位元組表示的資料流,然後TCP把資料流分割區成適當長度的報文段(通常受該計算機連線的網路的資料鏈路層的最大傳輸單元( MTU)的限制)。之後TCP把結果包傳給IP層,由它來通過網路將包傳送給接收端實體 的TCP層。TCP為了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認(ACK);如果傳送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的封包就被假設為已丟失將會被進行重傳。TCP用一個校驗和函數來檢驗資料是否有錯誤;在傳送和接收時都要計算校驗和。
TCP是因特網中的傳輸層協定,使用三次握手協定建立連線。當主動方發出SYN連線請求後,等待對方回答SYN+ACK ,並最終對對方的 SYN 執行 ACK 確認。這種建立連線的方法可以防止產生錯誤的連線,TCP使用的流量控制協定是可變大小的滑動視窗協定。 TCP三次握手的過程如下:
使用者端傳送SYN(SEQ=x)報文給伺服器端,進入SYN_SEND狀態。
伺服器端收到SYN報文,迴應一個SYN (SEQ=y)ACK(ACK=x+1)報文,進入SYN_RECV狀態。
使用者端收到伺服器端的SYN報文,迴應一個ACK(ACK=y+1)報文,進入Established狀態。
連線成功之後雙方即可互相傳輸位元組流,並隨時可關閉連線,傳輸的資料有以下特性
傳輸的資料被tcp分割成了最適合傳送的資料塊 傳遞給ip協定,這個傳送資料稱為 報文段 或 段
tcp作為可靠性連線,每次傳送資料段,會啟動一個定時器,每次接收資料段,會傳送一次確認,如果定時器沒有及時收到確認,則會重發資料
TCP將保持它首部和資料的檢驗和。這是一個端到端的檢驗和,目的是檢測資料在傳輸過程中的任何變化。如果收到段的檢驗和有差錯,TCP將丟棄這個報文段和不確認收到此報文段(希望發端超時並重發)。
兩個應用程式通過TCP連線交換8bit位元組構成的位元組流。TCP不在位元組流中插入記錄識別符號。我們將這稱為位元組流服務(bytestreamservice)。如果一方的應用程式先傳10位元組,又傳20位元組,再傳50位元組,連線的另一方將無法瞭解發方每次傳送了多少位元組。只要自己的接收快取沒有塞滿,TCP 接收方將有多少就收多少。一端將位元組流放到TCP連線上,同樣的位元組流將出現在TCP連線的另一端。
建立一個連線需要三次握手,而終止一個連線要經過四次揮手,這是由TCP的半關閉(half-close)造成的。具體過程如下所示。
某個應用程序首先呼叫close,稱該端執行「主動關閉」(active close)。該端的TCP於是傳送一個FIN分節,表示資料傳送完畢。
接收到這個FIN的對端執行 「被動關閉」(passive close),這個FIN由TCP確認。
注意:FIN的接收也作為一個檔案結束符(end-of-file)傳遞給接收端應用程序,放在已排隊等候該應用程序接收的任何其他資料之後,因為,FIN的接收意味著接收端應用程序在相應連線上再無額外資料可接收。
一段時間後,接收到這個檔案結束符的應用程序將呼叫close關閉它的通訊端。這導致它的TCP也傳送一個FIN。
接收這個最終FIN的原傳送端TCP(即執行主動關閉的那一端)確認這個FIN。 既然每個方向都需要一個FIN和一個ACK,因此通常需要4個分節。
「通常」是指,某些情況下,步驟1的FIN隨資料一起傳送,另外,步驟2和步驟3傳送的分節都出自執行被動關閉那一端,有可能被合併成一個分節。 在步驟2與步驟3之間,從執行被動關閉一端到執行主動關閉一端流動資料是可能的,這稱為「半關閉」(half-close)。 當一個Unix程序無論自願地(呼叫exit或從main函數返回)還是非自願地(收到一個終止本程序的訊號)終止時,所有開啟的描述符都被關閉,這也導致仍然開啟的任何TCP連線上也發出一個FIN。 無論是客戶還是伺服器,任何一端都可以執行主動關閉。通常情況是,客戶執行主動關閉,但是某些協定,例如,HTTP/1.0卻由伺服器執行主動關閉。
php可通過socket函數,swoole擴充套件,stream流函數進行建立tcp協定的socket,繫結網路卡埠,進行tcp伺服器端/使用者端操作 在php中,我們並不需要了解tcp的握手/揮手,我們只需要知道ip:port能連線/建立 一個tcp伺服器端/使用者端就行了
使用php的socket,我們可以直接傳送字串,接收的也是字串,其他一切都是語言,作業系統所需要做的事,
我們只需要處理好字串的完整性,例如我們使用php做tcp伺服器端
使用者端連線成功後,傳送了一個"easyswoole是一個非常好的swoole框架"的字串
而伺服器端每次只接收9個位元組,那第一次獲取只會接收到"easyswool"的殘缺字串,需要繼續獲取資料
http一次請求的過程大概如下:
使用者在瀏覽器輸入 www.easyswoole.com
dns伺服器解析/或者本機hosts,路由器hosts對比 獲得ip
瀏覽器存取預設埠80,則存取的tcp地址為 ip:80
tcp協定3次握手,建立連線
傳送一個http request請求頭
伺服器獲得http request請求頭,表明該次存取為http存取,解析http請求頭,獲得請求型別,請求格式,以及請求資料(cookie,get,post資料)
伺服器傳送response響應資料,主動斷開
瀏覽器接收response響應資料,解析響應文字型別,解析資料,斷開連線
https協定中,在請求以及響應時多了一層tls,ssl加密解密協定,預設埠從80變為了443
由於php大部分時候都是用於web伺服器,所以php開發者接觸最多的協定也就是基於tcp/ip協定的http協定了
在php初級程式設計師中,其實沒有詳細的瞭解過http協定,但是可以通過瀏覽器的f12->network去檢視http協定具體的請求頭,以及伺服器端傳送的響應頭
在沒有WebSocket協定之前,在網頁中,實現一個聊天室只能使用ajax 不斷輪詢,請求伺服器是否有資料產生,而這樣的實現方法會出現一系列的問題:
如果輪詢時間間隔太短,會導致使用者端和伺服器端在一個時間段內不斷的進行http tcp的握手/揮手動作和http 請求頭,響應頭的傳輸,大量消耗伺服器資源,如果使用者量大的情況,會造成伺服器的繁忙以至於宕機
使用者端每次只能通過傳送http 請求獲得伺服器是否有資料返回,且資料的及時性無法保證
在實現websocket連線過程中,需要通過瀏覽器發出websocket連線請求,然後伺服器發出迴應,這個過程通常稱為「握手」 。
在 WebSocket API,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。
兩者之間就直接可以資料互相傳送。在此WebSocket 協定中,為我們實現即時服務帶來了兩大好處:
Header: 互相溝通的Header是很小的-大概只有 2 Bytes
Server Push: 伺服器的推播,伺服器不再被動的接收到瀏覽器的請求之後才返回資料,而是在有新資料時就主動推播給瀏覽器。
UDP 是User Datagram Protocol的簡稱, 中文名是使用者資料包協定,是OSI(Open System Interconnection,開放式系統互聯) 參考模型中一種無連線的傳輸層協定,提供面向事務的簡單不可靠資訊傳送服務,IETF RFC 768是UDP的正式規範。UDP在IP報文的協定號是17。
UDP協定全稱是使用者資料包協定,在網路中它與TCP協定一樣用於處理封包,是一種無連線的協定。在OSI模型中,在第四層——傳輸層,處於IP協定的上一層。UDP有不提供封包分組、組裝和不能對封包進行排序的缺點,也就是說,當報文傳送之後,是無法得知其是否安全完整到達的。UDP用來支援那些需要在計算機之間傳輸資料的網路應用。包括網路視訊會議系統在內的眾多的客戶/伺服器模式的網路應用都需要使用UDP協定。UDP協定從問世至今已經被使用了很多年,雖然其最初的光彩已經被一些類似協定所掩蓋,但是即使是在今天UDP仍然不失為一項非常實用和可行的網路傳輸層協定。
與所熟知的TCP(傳輸控制協定)協定一樣,UDP協定直接位於IP(網際協定)協定的頂層。根據OSI(開放系統互連)參考模型,UDP和TCP都屬於傳輸層協定。UDP協定的主要作用是將網路資料流量壓縮成封包的形式。一個典型的封包就是一個二進位制資料的傳輸單位。每一個封包的前8個位元組用來包含報頭資訊,剩餘位元組則用來包含具體的傳輸資料。
udp和tcp都屬於傳輸層的協定,都位於ip協定的頂層,他們不同之處有:
udp是無連線協定,不需要進行tcp的握手
udp每次傳送最大長度是65535,而tcp在握手後可以源源不斷的傳送
udp協定使用報頭中的校驗值來保證資料的安全。校驗值首先在資料傳送方通過特殊的演演算法計算得出,在傳遞到接收方之後,還需要再重新計算。如果某個資料包在傳輸過程中被第三方篡改或者由於線路噪音等原因受到損壞,傳送和接收方的校驗計算值將不會相符,由此UDP協定可以檢測是否出錯。這與TCP協定是不同的,後者要求必須具有校驗值。
udp報文沒有可靠性保證、順序保證和流量控制欄位等,可靠性較差。但是正因為udp協定的控制選項較少,在資料傳輸過程中延遲小、資料傳輸效率高,適合對可靠性要求不高的應用程式,或者可以保障可靠性的應用程式,如DNS、TFTP、SNMP等。
在網路品質令人十分不滿意的環境下,UDP協定封包丟失會比較嚴重。而tcp會進行確認驗證,確保對方接收成功
udp可實現對閘道器內的所有主機進行廣播
前面有講到,多程序主要是在開發業務邏輯層面,並行處理多個任務的開發方式,什麼叫做開發業務邏輯層面呢?
在上面我們有講到,php-fpm是fast-cgi的程序管理器,啟動之後會啟動多個fast-cgi程序,等待任務處理
在php-fpm軟體層面,fast-cgi的多個程序就屬於多程序處理,但是,當使用者發起請求,
由nginx交給php-fpm處理請求時,在這個層面,每個請求其實只佔有一個php fast-cgi程序進行處理邏輯,對於執行業務邏輯的這個php程序,其實是單程序的.
同理,當我們直接執行一個php檔案時,預設是隻開啟了一個php程序進行執行php的程式碼
在傳統web模式下,php一向是單程序處理業務邏輯,只有在php-cli模式下,用於處理非同步任務,作為網路伺服器時,才可能用到多程序處理,所以,大部分phper都對php多程序的概念不熟悉
管道通訊,分為有名管道,無名管道等,可自行搜尋瞭解詳細
訊息佇列通訊,使用linux訊息佇列,通過sysvmsg擴充套件,可檢視: http://www.php20.cn/article/137
程序訊號通訊,可檢視: http://www.php20.cn/article/134
共用記憶體通訊,對映一段能被其他程序所存取的記憶體,這段共用記憶體由一個程序建立,但多個程序都可以存取。
共用記憶體是最快的 IPC 方式,它是針對其他程序間通訊方式執行效率低而專門設計的。
它往往與其他通訊機制,如訊號兩,配合使用,來實現程序間的同步和通訊。
通訊端通訊
第三方通訊,使用檔案操作,mysql,redis等方法也可實現通訊
協程
協程不是程序或執行緒,其執行過程更類似於子例程,或者說不帶返回值的函數呼叫。
一個程式可以包含多個協程,可以對比與一個程序包含多個執行緒,因而下面我們來比較協程和執行緒。
我們知道多個執行緒相對獨立,有自己的上下文,切換受系統控制;而協程也相對獨立,
有自己的上下文,但是其切換由自己控制,由當前協程切換到其他協程由當前協程來控制。
由上面的協程執行順序中的程式碼2,我們很容易發現,協程其實只是執行在一個程序中的函數,只是這個函數會被切換到下一個執行,可以這麼說:
協程只是一串執行在程序中的任務程式碼,只是這些任務程式碼可以交叉執行 注意,協程並不是多工並行,屬於多工序列,每個程序在一個時間只執行了一個任務
由於協程就是程序中一串任務程式碼,所以它的全域性變數,靜態變數等變數都是共用的,包括了php的全域性緩衝區.
所以,在開發之中,需要特別注意協程中的全域性變數,靜態變數,只要某一個協程內修改了,那將會影響全部的協程,在使用ob緩衝區函數攔截的時候,也得考慮是否會被其他協程的輸出給汙染.
用 協程執行順序中的程式碼2解釋,當task1給$_GET['name']賦值為1時,task2讀取$_GET['name']也會是1,task2將$_GET['name']賦值為2時,task3讀取$_GET['name']也會是2
在協程中,要特別注意不能共用一個I/O連線,否則會造成資料異常. 用協程執行順序中的程式碼2解釋,當task1,task2函數共用mysql連線,並都進行查詢時,由於協程是交叉執行的,可能會造成task1獲取到task1+task2查詢出來的資料,也可能會丟失部分資料,被task2獲取.
由於協程的交叉執行機制,各個協程的I/O連線都必須是獨立的,所以我們需要在每個協程都建立一個連線,但由於mysql,redis的連線數有限,以及連線的開啟關閉需要消耗大量資源,所以我們可以使用連線池方案實現共用連線(只要保證每個連線每次只有一個協程在使用即可)
推薦學習:
以上就是詳細整理swoole知識點(總結分享)的詳細內容,更多請關注TW511.COM其它相關文章!