laravel+swoole之websocket消息推送

1.首先安裝swoole擴展

Swoole-1.x需要 PHP-5.3.10 或更高版本
Swoole-2.x需要 PHP-7.0.0 或更高版本

公司環(huán)境是php5.6.31所以比較麻煩需要編譯安裝途戒,7以上直接使用命令
(pecl install swoole)

wget https://github.com/swoole/swoole-src/archive/v1.10.1.tar.gz
tar -zxvf v1.10.1.tar.gz
cd swoole-src-1.10.1
phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install

然后在php.ini添加swoole.so擴展即可

2.使用laravel的artisan創(chuàng)建命令

php artisan make:command Swoole   #創(chuàng)建一個命令swoole并會在app/Console/Commands增加一個Swoole.php的文件

Commands\Swoole::Class  #在Kernel.php里增加命令列表

3.運行socket服務

1.編輯app/Console/Command里的Swoole.php文件

<?php
namespace App\Console\Commands;

use Illuminate\Console\Command;

class Swoole extends Command
{
    public $ws;
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swoole {action?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'swoole';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $action = $this->argument('action');
        switch ($action) {
            case 'close':

                break;

            default:
                $this->start();
                break;
        }

    }
    public function start()
    {
        //創(chuàng)建websocket服務器對象芥映,監(jiān)聽0.0.0.0:9502端口
        $this->ws = new \swoole_websocket_server("0.0.0.0", 9502);

        //監(jiān)聽WebSocket連接打開事件
        $this->ws->on('open', function ($ws, $request) {
            var_dump($request->fd . "連接成功");
            // $ws->push($request->fd, "hello, welcome\n");
        });

        //監(jiān)聽WebSocket消息事件
        $this->ws->on('message', function ($ws, $frame) {
            // echo "Message: {$frame->data}\n";
            // $ws->push($frame->fd, "server: {$frame->data}");
            // var_dump($ws->connection_info($frame->fd));
            //fd綁定客戶端傳過來的標識uid
            $ws->bind($frame->fd, $frame->data);
        });

        $this->ws->on('request', function ($request, $response) {
                // 接收http請求從post獲取參數(shù)
                // 獲取所有連接的客戶端糯彬,驗證uid給指定用戶推送消息
                // token驗證推送來源捎琐,避免惡意訪問
                if ($request->post['token'] == ### ) {
                    $clients = $this->ws->getClientList();
                    $clientId = [];
                    foreach ($clients as $value) {
                        $clientInfo = $this->ws->connection_info($value);
                        if (array_key_exists('uid', $clientInfo) && $clientInfo['uid'] == $request->post['s_id']) {
                            $clientId[] = $value;
                        }
                    }
                    if (!empty($clientId)) {
                        foreach ($clientId as $v) {
                            $this->ws->push($v, $request->post['info']);
                        }
                    }
                }
            });

        //監(jiān)聽WebSocket連接關閉事件
        $this->ws->on('close', function ($ws, $fd) {
            echo "client:{$fd} is closed\n";
        });

        $this->ws->start();
    }
}
【注】此處為了結合app上傳數(shù)據(jù)時使用curl觸發(fā)request回調通知web端的實例所以使用了httpserver的onrequest事件患雏,如果以后有更好的辦法去觸發(fā)服務端實時主動推送蹋宦。

2.編輯html

<div id="test">
    <a href="javascript:void(0)">運行websocket</a>
</div>

$('#test').click(function(){
            if("WebSocket" in window){
                console.log("您的瀏覽器支持websocket\n");
                var ws = new WebSocket("ws://66.66.66.66:9502");//創(chuàng)建websocket對象 
                ws.onopen = function(){
                    // ws.send("連接已建立\n");
                    ws.send($("#content").attr("js-sid"));
                    console.log("數(shù)據(jù)發(fā)送中");
                }

                ws.onmessage = function(evt){
                    var recv_msg = evt.data;
                    console.log("接受到的數(shù)據(jù)為:"+recv_msg);
                }

                ws.onerror = function(evt,e){
                    console.log("錯誤信息為"+e);
                }

                ws.onclose = function(){
                    console.log("連接已關閉");
                }

            }else{
                console.log("您的瀏覽器不支持websocket\n");
            }
        });

3.curl方法(調用就行)

public function swooletest($param = ['s_id'=>2, 'info'=>'info'])
    {
        $param['token'] = ###;
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "http://127.0.0.1:9502");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        //設置post數(shù)據(jù)
        $post_data = $param;
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        curl_exec($ch);
        curl_close($ch);
    }

4.測試的時候直接在laravel的artisan所在目錄使用命令php artisan swoole即可啟動socket服務衔肢,然后頁面運行客戶端若专,最后調用curl推送數(shù)據(jù)久信。

4.成功之后

用supervisor守護swoole命令窖杀,或者nohup后臺啟動。

supervisor配置麻煩不過可以自動重啟裙士,nohup一條命令解決

nohup php artisan swoole &    #一條命令解決

此處說明幾個問題

1.此處我采用的是bind方法入客,當客戶端連接的時候send一個uid過來,然后在服務端處理的時候把uid和fd綁定在一起腿椎,當你想向某個客戶端發(fā)送數(shù)據(jù)時傳一個uid桌硫,通過uid找到fd進行指定發(fā)送,但是此處我用的是遍歷getClientList所有連接用戶(方法欠佳)的信息connection_info進行判定啃炸。希望能改善這種方法

2.因為是curl訪問httpserver的形式铆隘,所以為了避免惡意訪問,加一個token驗證肮帐。

3.推送的信息轉換成json再傳咖驮,即info值

4.本實例的賬戶可能會在多個終端登錄,有多個fd綁定uid训枢,所以遍歷推送push

參考

http://www.cnblogs.com/dcb3688/p/4608056.html

https://laravel-china.org/articles/4633/with-supervisor-use-swoole-to-create-a-websocket-server-in-laravel

https://wiki.swoole.com/wiki/page/397.html

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末托修,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恒界,更是在濱河造成了極大的恐慌睦刃,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件十酣,死亡現(xiàn)場離奇詭異涩拙,居然都是意外死亡,警方通過查閱死者的電腦和手機耸采,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門兴泥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虾宇,你說我怎么就攤上這事搓彻。” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵旭贬,是天一觀的道長怔接。 經常有香客問我,道長稀轨,這世上最難降的妖魔是什么扼脐? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮奋刽,結果婚禮上瓦侮,老公的妹妹穿的比我還像新娘。我一直安慰自己佣谐,他們只是感情好脏榆,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著台谍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吁断。 梳的紋絲不亂的頭發(fā)上趁蕊,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音仔役,去河邊找鬼掷伙。 笑死,一個胖子當著我的面吹牛又兵,可吹牛的內容都是我干的任柜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼沛厨,長吁一口氣:“原來是場噩夢啊……” “哼宙地!你這毒婦竟也來了?” 一聲冷哼從身側響起逆皮,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤宅粥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后电谣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秽梅,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年剿牺,在試婚紗的時候發(fā)現(xiàn)自己被綠了企垦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡晒来,死狀恐怖钞诡,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤臭增,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布懂酱,位于F島的核電站,受9級特大地震影響誊抛,放射性物質發(fā)生泄漏列牺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一拗窃、第九天 我趴在偏房一處隱蔽的房頂上張望瞎领。 院中可真熱鬧,春花似錦随夸、人聲如沸九默。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驼修。三九已至,卻和暖如春诈铛,著一層夾襖步出監(jiān)牢的瞬間乙各,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工幢竹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留耳峦,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓焕毫,卻偏偏與公主長得像蹲坷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邑飒,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容