前面的工作都準(zhǔn)備好后,就可以開(kāi)始入手swoole了。
現(xiàn)在就簡(jiǎn)單的對(duì)以下幾個(gè)模塊進(jìn)行簡(jiǎn)單的上手入門,當(dāng)然官方文檔也有對(duì)應(yīng)的使用方法,這里也只是簡(jiǎn)單的介紹上手。
HTML5的websocket文檔:https://www.runoob.com/html/html5-websocket.html
目錄:
Swoole的快速起步
? ? 1、tcp服務(wù)的學(xué)習(xí)和使用
? ? 2、udp服務(wù)的學(xué)習(xí)和使用
? ? 3、tcp、udp的介紹和它們的區(qū)別對(duì)比
? ? 4、tcp和udp客戶端的使用
? ? 5、Http服務(wù)的學(xué)習(xí)和使用
? ? 6、websocket服務(wù)的使用
正文:?tcp服務(wù)和udp服務(wù)的學(xué)習(xí)和使用
一、swoole支持的服務(wù)
swoole創(chuàng)建一個(gè)異步服務(wù)器程序,可以支持TCP、UDP、UnixSocket?3種協(xié)議,支持IPv4和IPv6,支持SSL/TLS單向雙向證書(shū)的隧道加密。使用者無(wú)需關(guān)注底層實(shí)現(xiàn)細(xì)節(jié),僅需要設(shè)置網(wǎng)絡(luò)事件的回調(diào)函數(shù)即可。
二、swoole運(yùn)行的流程圖(來(lái)自官方文檔)

三、進(jìn)程/線程結(jié)構(gòu)圖(來(lái)自官方文檔)


四、通過(guò)第二點(diǎn)的swoole流程圖,實(shí)現(xiàn)一個(gè)簡(jiǎn)單tcp服務(wù)的過(guò)程為:
(1)創(chuàng)建一個(gè)異步Server對(duì)象,具體可以參考server的函數(shù)文檔(server的相關(guān)函數(shù))
$serv = new Server(string $host, int $port = 0, int $mode = SWOOLE_PROCESS, int $sock_type = SWOOLE_SOCK_TCP);
(2)通過(guò)set函數(shù),設(shè)置swoole配置
function Server->set(array $setting);
一些set方法的說(shuō)明:
$serv->set(
????array(
????????'reactor_num' => 2, // 通過(guò)此參數(shù)來(lái)調(diào)節(jié)Reactor線程的數(shù)量,以充分利用多核
????????'worker_num' => 4, // 設(shè)置啟動(dòng)的Worker進(jìn)程數(shù)量。Swoole采用固定Worker進(jìn)程的模式
????????'backlog' => 128, // 此參數(shù)將決定最多同時(shí)有多少個(gè)待accept的連接,swoole本身accept效率是很高的,基本上不會(huì)出現(xiàn)大量排隊(duì)情況。
????????'max_request' => 50, // 此參數(shù)表示worker進(jìn)程在處理完n次請(qǐng)求后結(jié)束運(yùn)行。manager會(huì)重新創(chuàng)建一個(gè)worker進(jìn)程。此選項(xiàng)用來(lái)防止worker進(jìn)程內(nèi)存溢出。
????????'dispatch_mode' => 1, //1平均分配,2按FD取模固定分配,3搶占式分配,默認(rèn)為取模(dispatch=2)
????)
);
(3)注冊(cè)Server的事件回調(diào)函數(shù)on。
由于swoole是一個(gè)異步框架,里面的很多方法都是通過(guò)on函數(shù)綁定,通過(guò)回調(diào)進(jìn)行后續(xù)操作。
bool Server->on(string $event, mixed $callback);
操作的大概流程為:
$serv->on('Connect', 'my_onConnect'); // 監(jiān)聽(tīng)連接進(jìn)入事件 ,tcp需要連接,udp不需要連接操作
$serv->on('Receive', 'my_onReceive'); // 監(jiān)聽(tīng)數(shù)據(jù)接收事件
$serv->on('Close', 'my_onClose'); // 監(jiān)聽(tīng)連接關(guān)閉事件
(4)啟動(dòng)服務(wù)
$serv->start();
五、簡(jiǎn)單示例
以上方法的簡(jiǎn)單實(shí)現(xiàn)示例(摘自官方文檔):
<?php
????//創(chuàng)建Server對(duì)象,監(jiān)聽(tīng) 127.0.0.1:9501端口
????$serv = new Swoole\Server("127.0.0.1", 9501);
????//監(jiān)聽(tīng)連接進(jìn)入事件
????$serv->on('Connect', function ($serv, $fd) { echo "Client: Connect.\n"; });
????//監(jiān)聽(tīng)數(shù)據(jù)接收事件
????$serv->on('Receive', function ($serv, $fd, $from_id, $data) {
????????????$serv->send($fd, "Server: ".$data);
????});
????//監(jiān)聽(tīng)連接關(guān)閉事件
????$serv->on('Close', function ($serv, $fd) {
????????echo "Client: Close.\n";
????});
????//啟動(dòng)服務(wù)器
????$serv->start();
?>
六、udp服務(wù)的簡(jiǎn)單示例
tcp和udp服務(wù)雖然都是使用swoole_server服務(wù),但是區(qū)別在于創(chuàng)建一個(gè)異步服務(wù)時(shí),指定模式為UDP:?SWOOLE_SOCK_UDP。默認(rèn)的模式是SWOOLE_SOCK_TCP。
需要注意的是:UDP服務(wù)器與TCP服務(wù)器不同,UDP沒(méi)有連接的概念。啟動(dòng)Server后,客戶端無(wú)需Connect,直接可以向Server監(jiān)聽(tīng)的9502端口發(fā)送數(shù)據(jù)包。對(duì)應(yīng)的事件為onPacket。
//創(chuàng)建Server對(duì)象,監(jiān)聽(tīng) 127.0.0.1:9502端口,類型為SWOOLE_SOCK_UDP
$serv = new swoole_server("127.0.0.1", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);
//監(jiān)聽(tīng)數(shù)據(jù)接收事件
$serv->on('Packet', function ($serv, $data, $clientInfo) {
$serv->sendto($clientInfo['address'], $clientInfo['port'], "Server ".$data);
var_dump($clientInfo);
});
//啟動(dòng)服務(wù)器
$serv->start();
七、tcp協(xié)議和udp協(xié)議的區(qū)別對(duì)比
1、主要區(qū)別:
(1)TCP面向連接(如打電話要先撥號(hào)建立連接);UDP是無(wú)連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接;
(2)TCP提供可靠的服務(wù)。也就是說(shuō),通過(guò)TCP連接傳送的數(shù)據(jù),無(wú)差錯(cuò),不丟失,不重復(fù),且按序到達(dá);UDP盡最大努力交付,即不保證可靠交付;
TCP通過(guò)校驗(yàn)和,重傳控制,序號(hào)標(biāo)識(shí),滑動(dòng)窗口、確認(rèn)應(yīng)答實(shí)現(xiàn)可靠傳輸。如丟包時(shí)的重發(fā)控制,還可以對(duì)次序亂掉的分包進(jìn)行順序控制。
(3)UDP具有較好的實(shí)時(shí)性,工作效率比TCP高,適用于對(duì)高速傳輸和實(shí)時(shí)性有較高的通信或廣播通信。
(4)每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對(duì)一,一對(duì)多,多對(duì)一和多對(duì)多的交互通信
(5)TCP對(duì)系統(tǒng)資源要求較多,UDP對(duì)系統(tǒng)資源要求較少。
2、為什么UDP有時(shí)比TCP更有優(yōu)勢(shì)?
UDP以其簡(jiǎn)單、傳輸快的優(yōu)勢(shì),在越來(lái)越多場(chǎng)景下取代了TCP,如實(shí)時(shí)游戲。
(1)網(wǎng)速的提升給UDP的穩(wěn)定性提供可靠網(wǎng)絡(luò)保障,丟包率很低,如果使用應(yīng)用層重傳,能夠確保傳輸?shù)目煽啃浴?/p>
(2)TCP為了實(shí)現(xiàn)網(wǎng)絡(luò)通信的可靠性,使用了復(fù)雜的擁塞控制算法,建立了繁瑣的握手過(guò)程,由于TCP內(nèi)置的系統(tǒng)協(xié)議棧中,極難對(duì)其進(jìn)行改進(jìn)。
采用TCP,一旦發(fā)生丟包,TCP會(huì)將后續(xù)的包緩存起來(lái),等前面的包重傳并接收到后再繼續(xù)發(fā)送,延時(shí)會(huì)越來(lái)越大,基于UDP對(duì)實(shí)時(shí)性要求較為嚴(yán)格的情況下,采用自定義重傳機(jī)制,能夠把丟包產(chǎn)生的延遲降到最低,盡量減少網(wǎng)絡(luò)問(wèn)題對(duì)游戲性造成影響。
3、為什么TCP不適用于實(shí)時(shí)傳輸?
TCP影響實(shí)時(shí)性不是因?yàn)槲帐窒臅r(shí)間。握手一開(kāi)始建立完就沒(méi)事了
一般來(lái)說(shuō),單位時(shí)間內(nèi)傳輸?shù)臄?shù)據(jù)流量比較平滑。 TCP依賴滑動(dòng)窗口進(jìn)行流量控制,滑動(dòng)窗口大小是自適應(yīng)的,影響滑動(dòng)窗口主要有兩個(gè)因素,一是網(wǎng)絡(luò)延時(shí),二是傳輸速率,滑動(dòng)窗口的大小與延時(shí)成正比,與傳輸速率也成正比。在給定的網(wǎng)絡(luò)環(huán)境下,延時(shí)可以認(rèn)為是固定的,因此滑動(dòng)窗口僅與傳輸速率有關(guān),當(dāng)傳輸實(shí)時(shí)數(shù)據(jù)時(shí),因?yàn)閿?shù)據(jù)流通量比較固定,所以這時(shí)TCP上的滑動(dòng)窗口會(huì)處于一個(gè)不大不小的固定值,這個(gè)值大小恰好保證當(dāng)前生產(chǎn)的數(shù)據(jù)實(shí)時(shí)傳輸?shù)綄?duì)方,當(dāng)出現(xiàn)網(wǎng)絡(luò)丟包時(shí),按TCP協(xié)議(快速恢復(fù)),滑動(dòng)窗口將減少到原來(lái)的一半,因此速率立刻減半,此時(shí)發(fā)送速率將小于數(shù)據(jù)生產(chǎn)速率,一些數(shù)據(jù)將滯留在發(fā)送端,然后滑動(dòng)窗口將不斷增大,直到積累的數(shù)據(jù)全部發(fā)送完畢。上述過(guò)程即為典型的TCP流量抖動(dòng)過(guò)程,對(duì)于實(shí)時(shí)傳輸影響很大,可能形成較大的突發(fā)時(shí)延,從用戶感觀角度來(lái)說(shuō),就是有時(shí)比較流暢,但有時(shí)卡(“抖一下”,并且比較嚴(yán)重),因此實(shí)時(shí)傳輸通常不使用TCP。
4、udp和tcp可以應(yīng)用的場(chǎng)景:
比如普通的會(huì)議視頻圖像,當(dāng)然首選UDP,畢竟丟幾包無(wú)所謂。
如果傳輸文件等,不能丟包,用TCP協(xié)議。
5、擴(kuò)展:TCP協(xié)議的三次握手和四次揮手
(1)三次握手
為了準(zhǔn)確無(wú)誤的將數(shù)據(jù)發(fā)送到指定IP處,TCP協(xié)議采用了三次握手的策略,如下步驟所示:
①客戶端采用TCP協(xié)議將帶有SYN標(biāo)志的數(shù)據(jù)包發(fā)送給服務(wù)器,等待服務(wù)器的確認(rèn)。
②服務(wù)器端在收到SYN的數(shù)據(jù)包后,必須確認(rèn)SYN,即自己發(fā)送的ACK標(biāo)志,同時(shí),自己也將會(huì)向客戶端發(fā)送一個(gè)SYN標(biāo)志。
③客戶端在接收到服務(wù)器短的SYN+ACK包后,自己會(huì)向服務(wù)器發(fā)送ACK包,完成三次握手。那么客戶端和服務(wù)器正式建立了連接,開(kāi)始傳輸數(shù)據(jù)。
三次握手的圖如下所示:

(2)四次揮手
四次揮手是用來(lái)斷開(kāi)服務(wù)器和客戶端之間的通信的,之所以要斷開(kāi)連接,是因?yàn)門CP/IP 協(xié)議是要占用端口號(hào)的,而計(jì)算機(jī)的端口卻是有限的,不進(jìn)行斷開(kāi)的話,勢(shì)必會(huì)造成計(jì)算機(jī)資源的浪費(fèi)。
①在整個(gè)通信的過(guò)程中,誰(shuí)先發(fā)起請(qǐng)求,誰(shuí)就是客戶端。
當(dāng)客戶端的數(shù)據(jù)傳輸?shù)轿膊繒r(shí),客戶端向服務(wù)器發(fā)送帶有FIN標(biāo)志的數(shù)據(jù)包,使其明白自己準(zhǔn)備斷開(kāi)通信了。
②因?yàn)門CP的通信是使用全雙工通信的WebSocket,所以在斷開(kāi)連接的時(shí)候也應(yīng)該是雙向的;當(dāng)服務(wù)器收到帶有FIN標(biāo)志的數(shù)據(jù)包時(shí),其必不會(huì)直接發(fā)送FIN標(biāo)志斷開(kāi)通信的請(qǐng)求,而是先發(fā)送一個(gè)帶有ACK標(biāo)志的應(yīng)答信息,使客戶端明白服務(wù)器還有數(shù)據(jù)要進(jìn)行發(fā)送。
③當(dāng) 服務(wù)器的數(shù)據(jù)發(fā)送完成后,向客戶端發(fā)送帶有FIN標(biāo)志的數(shù)據(jù)包,通知客戶端斷開(kāi)連接。
④這一次揮手是我覺(jué)得四次揮手中設(shè)計(jì)的最巧妙的一次。
當(dāng)客戶端收到FIN后,擔(dān)心網(wǎng)絡(luò)上某些不可控制的因素導(dǎo)致服務(wù)器不知道他要斷開(kāi)連接,會(huì)發(fā)送ACK進(jìn)行確認(rèn),同時(shí)把自己設(shè)置成TIME_WAIT狀態(tài)并啟動(dòng)定時(shí)器,**在TCP的定時(shí)器到達(dá)后客戶端并沒(méi)有接收到請(qǐng)求,會(huì)重新發(fā)送;當(dāng)服務(wù)器收到請(qǐng)求后就斷開(kāi)連接;當(dāng)客戶端等待2MLS(兩倍報(bào)文最大生存時(shí)間)后,沒(méi)有收到請(qǐng)求重傳的請(qǐng)求后,客戶端這邊就斷開(kāi)連接,**整個(gè)TCP通信就結(jié)束了。
四次揮手的圖如下所示:
