配合 Supervisor,在 Laravel 裡使用 Swoole 建立一個 websocket 伺服器

Lzg發表於2017-05-06

想實現一個wesocket的聊天室,看到網上說swoole對這方面的支援挺好,所以試一下把laravel與swoole結合一下,只是做了個嘗試,可以執行成功,具體細節尚未完善。

1、swoole安裝請參考官網文件

https://wiki.swoole.com/

2、參考最近手冊在laravel裡建立一個新的命令swoole

http://laravelacademy.org/post/6842.html
建立一個名叫swoole的命令 php artisan make:command Swoole
在Kernel.php裡增加命令列表

protected $commands = [
        Commands\Swoole::Class
];

修改swoole檔案如下:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class Swoole extends Command
{
    /**
     * 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()
    {
        //建立websocket伺服器物件,監聽0.0.0.0:9502埠
        $ws = new \swoole_websocket_server("0.0.0.0", 9502);

        //監聽WebSocket連線開啟事件
        $ws->on('open', function ($ws, $request) {
            // var_dump($request->fd, $request->get, $request->server);
            $ws->push($request->fd, "hello, welcome\n");
        });

        //監聽WebSocket訊息事件
        $ws->on('message', function ($ws, $frame) {
            echo "Message: {$frame->data}\n";
            $ws->push($frame->fd, "server: {$frame->data}");
        });

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

        $ws->start();
    }
}

這個時候就可以在 php artisan list 裡查到swoole命令了,具體看手冊。

3、詳細解讀

a、start()函式里呼叫了swoole的swoole_websocket_server類建立一個websocket伺服器,監聽9502埠
b、幾個事件請看swoole的官方手冊,其實就是監聽一個socket連線並響應訊息。這是一個聊天室的雛形,可以在裡使用laravel的任意功能來完成使用者聊天室的定位,並給所有人發訊息,形成實時聊天功能
c、比如使用者登陸後傳送訊息時附帶一個rid(聊天室)過來,程式把fd與rid對應,並給所有rid對應的fd廣播訊息

4、最好使用supervisor來守護swoole命令,使其在後臺一直執行

我的配置如下:

[program:swoole-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/artisan swoole
autostart=true
autorestart=true
user=apache
numprocs=1 //注意這裡一定只有一個,埠的問題~~
redirect_stderr=true
stdout_logfile=/path/worker.log

5、在html裡實現聊天功能,只能自己跟自己聊,試試長連線,要結合程式請自己嘗試~

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="msg"></div>
<input type="text" id="text">
<input type="submit" value="傳送資料" onclick="song()">
<p>adfssa</p>
</body>
<script>
    document.querySelector("body").style.fontSize = '28px';
    var msg = document.getElementById("msg");
    var wsServer = 'ws://100.100.100.100:9502/'
    //呼叫websocket物件建立連線:
    //引數:ws/wss(加密)://ip:port (字串)
    var websocket = new WebSocket(wsServer);
    //onopen監聽連線開啟
    websocket.onopen = function (evt) {
        //websocket.readyState 屬性:
        /*
        CONNECTING    0    The connection is not yet open.
        OPEN    1    The connection is open and ready to communicate.
        CLOSING    2    The connection is in the process of closing.
        CLOSED    3    The connection is closed or couldn't be opened.
        */
        msg.innerHTML = websocket.readyState;
    };

    function song(){
        var text = document.getElementById('text').value;
        document.getElementById('text').value = '';
        //向伺服器傳送資料
        websocket.send(text);
    }
      //監聽連線關閉
//    websocket.onclose = function (evt) {
//        console.log("Disconnected");
//    };

    //onmessage 監聽伺服器資料推送
    websocket.onmessage = function (evt) {
        msg.innerHTML += evt.data +'<br>';
//        console.log('Retrieved data from server: ' + evt.data);
    };
//監聽連線錯誤資訊
//    websocket.onerror = function (evt, e) {
//        console.log('Error occured: ' + evt.data);
//    };

</script>
</html>

謝謝各位大神們創造出來這麼多好用的庫、擴充套件

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章