咱們看Swoole官方文檔入門指引->快速起步->建立TCP服務器,把文檔的示例代碼跑一次,看下效果:php
server.php
html
<?php //建立Server對象,監聽 127.0.0.1:9501端口 $serv = new Swoole\Server("127.0.0.1", 9501); // 設置自定義參數 // @doc https://wiki.swoole.com/wiki/page/13.html $serv->set([ 'worker_num' => 8, // worker 進程數爲cpu 1-4倍 'max_request' => 10000, ]); //監聽鏈接進入事件 /** * $fd 客戶端鏈接的惟一標識 * $reactor_id 線程ID */ $serv->on('Connect', function ($serv, $fd, $reactorId) { echo "Client: {$reactorId}-{$fd}-Connect.\n"; }); //監聽數據接收事件 $serv->on('Receive', function ($serv, $fd, $reactorId, $data) { $serv->send($fd, "Server: {$reactorId} - {$fd} ".$data); }); //監聽鏈接關閉事件 $serv->on('Close', function ($serv, $fd) { echo "Client: Close.\n"; }); //啓動服務器 $serv->start();
咱們先開啓服務,而後再經過 telnet
命令分別開啓兩個窗口鏈接該服務react
root@5ee6bfcc1310:/work/study/code/swoole/demo/server# php server.php Client: 0-1-Connect. Client: 1-2-Connect.
0號客戶端:算法
root@5ee6bfcc1310:/# telnet 127.0.0.1 9501 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. hello Server: 0 - 1 hello
1號客戶端:緩存
root@5ee6bfcc1310:/# telnet 127.0.0.1 9501 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. hello Server: 1 - 2 hello
tcp_client.php
服務器
<?php // 該文件模擬 telnet 127.0.0.1 9501 命令進行請求服務端 // 鏈接 Swoole tcp 服務 $client = new Swoole\Client(SWOOLE_SOCK_TCP); if(!$client->connect("127.0.0.1", 9501)){ echo 'Connect error'; exit; } // php cli常量 fwrite(STDOUT, "請輸入消息"); $msg = trim(fgets(STDIN)); // 發送消息給 tcp server 服務器 $client->send($msg); // 接收來自server的數據 $res = $client->recv(); echo $res;
執行該腳本:swoole
php tcp_client.php
打印:網絡
root@5ee6bfcc1310:~# /work/study/soft/php/bin/php /work/study/code/swoole/demo/client/tcp_client.php 請輸入消息3 Server: 0 - 3 3
UDP服務器與TCP服務器不一樣,UDP沒有鏈接的概念。啓動Server後,客戶端無需Connect,直接能夠向Server監聽的9502端口發送數據包。對應的事件爲onPacket。socket
咱們看Swoole官方文檔入門指引->快速起步->建立UDP服務器tcp
udp_server.php
<?php //建立Server對象,監聽 127.0.0.1:9502端口,類型爲SWOOLE_SOCK_UDP $serv = new swoole_server("127.0.0.1", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP); //監聽數據接收事件 $serv->on('Packet', function ($serv, $data, $clientInfo) { $serv->sendto($clientInfo['address'], $clientInfo['port'], "Server ".$data); var_dump($clientInfo); }); //啓動服務器 $serv->start();
啓動服務:
php udp_server.php
UDP服務器可使用 netcat -u
來鏈接測試
netcat -u 127.0.0.1 9502 hello Server: hello
當客戶端鏈接發送了數據以後,服務端會打印出客戶端的相關信息:
# php udp_server.php array(4) { ["server_socket"]=> int(3) ["server_port"]=> int(9502) ["address"]=> string(9) "127.0.0.1" ["port"]=> int(40627) }
TCP(Transmission Control Protocol 傳輸控制協議):是一種面向鏈接的,可靠的,基於字節流的傳輸通訊協議。
UDP(User Datagram Protocol 用戶數據報協議):是一種無鏈接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務。
面向鏈接
的(在客戶端和服務器之間傳輸數據以前要先創建鏈接),UDP是無鏈接
的(發送數據以前不須要先創建鏈接)實時性
,工做效率比TCP高,適用於對高速傳輸和實時性比較高的通信或廣播通訊。隨着網速的提升,UDP使用愈來愈多。UDP以其簡單、傳輸快的優點,在愈來愈多場景下取代了TCP,如實時遊戲。
(1)網速的提高給UDP的穩定性提供可靠網絡保障,丟包率很低,若是使用應用層重傳,可以確保傳輸的可靠性。
(2)TCP爲了實現網絡通訊的可靠性,使用了複雜的擁塞控制算法,創建了繁瑣的握手過程,因爲TCP內置的系統協議棧中,極難對其進行改進。
採用TCP,一旦發生丟包,TCP會將後續的包緩存起來,等前面的包重傳並接收到後再繼續發送,延時會愈來愈大,基於UDP對實時性要求較爲嚴格的狀況下,採用自定義重傳機制,可以把丟包產生的延遲降到最低,儘可能減小網絡問題對遊戲性形成影響。
TCP影響實時性不是由於握手消耗時間。握手一開始創建完就沒事了。
通常來講,單位時間內傳輸的數據流量比較平滑。 TCP依賴滑動窗口進行流量控制,滑動窗口大小是自適應的,影響滑動窗口主要有兩個因素,一是網絡延時,二是傳輸速率,滑動窗口的大小與延時成正比,與傳輸速率也成正比。在給定的網絡環境下,延時能夠認爲是固定的,所以滑動窗口僅與傳輸速率有關,當傳輸實時數據時,由於數據流通量比較固定,因此這時TCP上的滑動窗口會處於一個不大不小的固定值,這個值大小剛好保證當前生產的數據實時傳輸到對方,當出現網絡丟包時,按TCP協議(快速恢復),滑動窗口將減小到原來的一半,所以速率馬上減半,此時發送速率將小於數據生產速率,一些數據將滯留在發送端,而後滑動窗口將不斷增大,直到積累的數據所有發送完畢。上述過程即爲典型的TCP流量抖動過程
,對於實時傳輸影響很大,可能造成較大的突發時延,從用戶感觀角度來講,就是有時比較流暢,但有時卡(「抖一下」,而且比較嚴重),所以實時傳輸一般不使用TCP。
好比普通的會議視頻圖像、音頻、普通數據,固然首選UDP,畢竟丟幾包無所謂,若是傳輸文件等,不能丟包,用TCP。
UDP它不屬於鏈接型協議,於是具備資源消耗小,處理速度快的優勢,因此一般音頻、視頻和普通數據在傳送時使用UDP較多,由於它們即便偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。
傳輸層沒法保證數據的可靠傳輸,只能經過應用層來實現了。實現的方式能夠參照tcp可靠性傳輸的方式,只是實現不在傳輸層,實現轉移到了應用層。