當前位置:才華齋>計算機>php語言>

如何使用PHP構建一個高效能的彈幕後端服務大綱

php語言 閱讀(8.86K)

隨著WEB2.0的流行,現在很多網站都流行使用“彈幕”這種形式來實現互動。 彈幕(barrage),中文流行詞語,原意指用大量或少量火炮提供密集炮擊。大量以字幕彈(dàn)出形式顯示的評論同時在螢幕上飄過的現象也被稱為彈幕。下面是小編為大家帶來的關於如何使用PHP構建一個高效能的彈幕後端服務的知識,歡迎閱讀。

如何使用PHP構建一個高效能的彈幕後端服務大綱
  如何使用PHP構建一個高效能的彈幕後端服務

作為PHPer的我們,看到現在各種網站都有酷炫的彈幕飛過,我們是不是也想給自己的網站加入彈幕功能呢?

首先彈幕的後端其實說白了和公共聊天室的後端原理十分相似,都是一個客戶端傳送訊息給服務端,服務端再將收到的訊息廣播給其他的客戶端。對於後端來說他們幾乎沒區別,區別就在於前端。

好在我們有一個前端彈幕外掛,這個外掛是一個jquery外掛,github地址:,基本上會使用jquery語法,看看示例程式碼就可以傻瓜化使用。

前端已經有了解決方案,但是後端呢?前端如何與後端通訊?用傳統的ajax輪詢嗎?不行,這樣效率太低,想想各大火爆的直播平臺都是同一時間幾萬人線上,幾千人同時發彈幕,如果靠ajax輪詢一個php介面的話伺服器會吃不消的。且彈幕訊息儲存方案略顯複雜,有人問為什麼要儲存呢?因為ajax使用的HTTP協議是無狀態協議,A客戶端和B客戶端之間對於伺服器來說沒有任何標誌,如果伺服器要確保A客戶端和B客戶端分別在兩次請求的時候伺服器只返回這兩個客戶端沒有獲取過的彈幕訊息,那麼伺服器端就必須使用一個快取來標識某某客戶端看過哪條彈幕訊息。綜上所述ajax可以實現小規模的彈幕通訊方案,但是很麻煩。

好在最新的HTML5中加入了WebSocket協議,我們可以通過WebSocket這種基於HTTP協議之上的即時通訊協議來替代ajax這種傳統的我問你答的老舊通訊模式。而我們是PHPer,對於我們這種只懂PHP的人該如何編寫WebSocket服務端呢?好在我們又得知PHP有一個Swoole擴充套件,我們在PHP語言中使用它可以很方便的構建一個WebSocket服務端。

關於Swoole的.介紹可以參照他的官網,下面引用官網對它的一段簡短的介紹。

PHP的非同步、並行、高效能網路通訊引擎,使用純C語言編寫,提供了PHP語言的非同步多執行緒伺服器,非同步TCP/UDP網路客戶端,非同步MySQL,非同步Redis,資料庫連線池,AsyncTask,訊息佇列,毫秒定時器,非同步檔案讀寫,非同步DNS查詢。 Swoole內建了Http/WebSocket伺服器端/客戶端、Http2.0伺服器端。

Swoole可以廣泛應用於網際網路、行動通訊、企業軟體、雲端計算、網路遊戲、物聯網(IOT)、車聯網、智慧家居等領域。 使用PHP+Swoole作為網路通訊框架,可以使企業IT研發團隊的效率大大提升,更加專注於開發創新產品。

先別被Swoole這麼多的功能嚇到了。我們先關注這裡面的重點

  Swoole內建了Http/WebSocket伺服器端/客戶端

意味著我們可以通過它構建WebSocket的服務端。看到這裡我們是不是就急急忙忙去拿官網的WebSocket服務端程式碼做測試呢?不,Swoole是一個PHP擴充套件,意味著我們還得去安裝它。是不是直接去下載so檔案然後在中加入extension=就可以了呢?還不是,我們先去看看Swoole擴充套件的依賴,這也是我們使用任何語言的任何外部包,外部模組,外部擴充套件最先要了解的問題。

  環境依賴

僅支援Linux,FreeBSD,MacOS,3類作業系統

Linux核心版本2.3.32以上

PHP5.3.10以上版本,包括PHP7

gcc4.4以上版本或者clang

cmake2.4+,編譯為作為C/C++庫時需要使用cmake

  PHP版本依賴

swoole僅支援PHP5.3.10或更高版本,建議使用PHP5.4+

swoole不依賴php的stream、sockets、pcntl、posix、sysvmsg等擴充套件。PHP只需安裝最基本的擴充套件即可

意味著我們Windows下是無法使用這個擴充套件了(其實可以藉助cygwin在win下使用swoole,但是考慮到我們使用swoole擴充套件就是為了效能,也為了熟悉以後的生產環節部署做準備,強烈推薦在linux下開發),那麼我們把開發環境轉移到Linux下進行吧。

接著還要求Linux核心版本為2.3.32以上,PHP為5.3.10以上,那麼我們就用最新的CentOS吧,這個版本的yum安裝的php直接就是PHP7最新版,根本無需考慮其他問題,當然你喜歡圖形介面,用Ubuntu也可以。其他的基本上最新的Linux發行版都是符合版本要求的。

接著我們便來安裝這個擴充套件,推薦使用PECL來安裝,只需要一條

pecl install swoole

即可,非常方便。當然你要編譯安裝,具體步驟請參考

安裝完擴充套件之後在命令列下輸入

php -m

檢查,如果有swoole那麼說明安裝成功了。

接下來就正式開始我們的編碼旅程了。

開始編碼旅程之前我們先看看最基礎的效果原型是什麼樣子

沒錯就是這個樣子,兩個瀏覽器之前完全獨立使用Websocket連線服務端,因此對於服務端來說這兩個瀏覽器就相當於兩個完全處在不同機器上的客戶端。

效果看完了就開始來講程式碼吧。

我們先看看官網的WebSocket服務端示例程式碼。

$serv = new SwooleWebsocketServer("", 9502);

$serv->on('Open', function($server, $req) {

echo "connection open: ".$req->fd;

});

$serv->on('Message', function($server, $frame) {

echo "message: ".$frame->data;

$server->push($frame->fd, json_encode(["hello", "world"]));

});

$serv->on('Close', function($server, $fd) {

echo "connection close: ".$fd;

});

$serv->start();

我們看到這個程式碼的第一行先是new了一個WebSocket服務端物件,並且在構造方法中的第一個引數指定了服務端監聽的IP,第二個引數指定了服務端監聽的埠。然後使用on方法為每一個事件設定了回撥函式,最後一行start方法正式開始執行服務端。

這種寫法非常像Javascript裡面的非同步呼叫,這也是Swoole中的事件驅動非同步非阻塞特性,正因為是這種特性,每一個獨立的事件(請求)會在服務端接收到之後分別非同步處理,他們之間無需互相等待,這也是Swoole效能高的原因所在。

我們來分別剖析一下每一個事件的含義。

$serv->on('Open', function($server, $req) {

echo "connection open: ".$req->fd;

});

顧名思義,Open表示開啟一個新的連結,並且在事件觸發之後echo出連線上服務端的客戶端id,該客戶端唯一id為回撥函式第二個引數中的fd欄位。這也是服務端區分客戶端的唯一id。

$serv->on('Message', function($server, $frame) {

echo "message: ".$frame->data;

$server->push($frame->fd, json_encode(["hello", "world"]));

});

同樣顧名思義,Message表示訊息到達服務端的事件,並且在事件觸發之後echo出發送給服務端的資料,該資料為回撥函式第二個引數的data欄位。另外我們還看到它呼叫了$server->push,這是回撥函式的第一個引數中的push方法,它是一個服務端給客戶的傳送資料的方法,第一個引數為要傳送的客戶端id,第二個為要傳送的資料,這裡的含義是向發給服務端訊息的那個客戶端傳送["hello", "world"]這個陣列(方括號寫陣列為PHP5.4的新特性,如果你是PHP5.3請使用傳統的array工廠函式生成陣列)經過json序列化之後的資料。

$serv->on('Close', function($server, $fd) {

echo "connection close: ".$fd;

});

最後一個事件Close更加容易理解,就是關閉事件,當然關閉的不是服務端,而是客戶端,可以理解為客戶端與服務端斷開連線的事件。回撥函式中的程式碼含義為echo出與服務端斷開連線的那個客戶端id。

基本的API都清楚了,下面就直接看程式碼吧,短短二十行而已。

$server = new swoole_websocket_server("", 1997);

$server->on('open', function (swoole_websocket_server $server, $request) {

echo "server: handshake success with fd{$request->fd}";

//$request->fd 是客戶端id

});

$server->on('message', function (swoole_websocket_server $server, $frame) {

echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},

fin:{$frame->finish}";

//$frame->fd 是客戶端id,$frame->data是客戶端傳送的資料

//服務端向客戶端傳送資料是用$server->push( '客戶端id' , '內容')

$data = $frame->data;

foreach($server->connections as $fd){

$server->push($fd , $data);//迴圈廣播

}});

$server->on('close', function ($ser, $fd) {

echo "client {$fd} closed";

});

$server->start();

這裡最核心的廣播程式碼其實還用到了一個之前沒有提到過的成員,也就是swoole_websocket_server物件的connections成員,這個成員中儲存了所有已連線上該WebSocket服務端的fd,也就是客戶端id。因此我們只要在message事件中使用foreach遍歷該成員,迴圈將所有服務端收到的彈幕訊息都發送給其他已連線上該服務端的客戶端即可。

後端講完了再講講前端吧。

前端程式碼也不是很多

var ws = new WebSocket("ws://");

en = function(){

("握手成功");

('hello world!!!');

};

ssage = function(e){

("message:" + );

var time = jQuery('#danmu')("nowtime") + 1;

var text_obj = '{ "text":"' + + '" , "color":"green" ,"size":"1","position":"0","time":"' + time + '" ,"isnew":" "}'; //構造加上了innew屬性的字串danmu物件

(text_obj);

var new_obj = eval('(' + text_obj + ')'); //轉化為js物件

jQuery('#danmu')u("add_danmu", new_obj); //向外掛中新增該danmu物件

};

ror = function(){

("error");

};

核心程式碼都在這裡,使用new WebSocket("ws://")建立一個WebSocket客戶端連線物件,通過該物件的各種事件進行對應的操作,和服務端是不是很像?更多程式碼解釋可以參考原始碼中的註釋,這裡不做更多介紹。

看到這裡相信作為一名PHPer的你也可以開發出屬於自己的彈幕系統了。這裡展示的只是一個最基礎最原始的彈幕平臺。我們也瞭解到了使用PHP開發一個彈幕平臺需要涉及到的技術有WebSocket,Swoole擴充套件,甚至碰到了很多初級開發者平時不怎麼接觸的工具,比如說PECL,比如說Linux。

其實PHP結合Swoole擴充套件還可以做很多事情,比如說對接各種家電,對接各種硬體介面實現在Web端實時控制家電,又比如說結合樹莓派做智慧小車,通過web端進行遙控等等,各種新奇的玩法等你發現。誰說PHP只能做Web開發?PHP擁有了Swoole擴充套件其實能做的事情還有很多,Swoole就像他的宣傳標題一樣:重新定義PHP。