首頁  >  文章  >  php框架  >  使用 Workman 做一個聊天室

使用 Workman 做一個聊天室

步履不停
步履不停原創
2019-06-21 14:52:236112瀏覽

使用 Workman 做一個聊天室

為什麼要寫這篇文章?

我學習Workman好幾次了,每次都失敗(沒做成想要的功能,原諒我比較笨)。但這次也花了好幾個小時,把之前沒做成的功能實現了。其實就是兩個簡單的功能:一對一發送訊息,廣播訊息(群組聊天)。這個功能用swoole早都實現了,也是由於之前一直想用 think-worker 的原因,想想還是得自己琢磨才行,人家做好的框架或許是個閹割版。

別問我為什麼不用swoole,因為 workman 可以在Windows中運作。

(1)首先,得簡單說說 thinkphp workerman 的安裝。

安裝thinkphp5.1

composer create-project topthink/think=5.1.x-dev tp5andworkman

安裝think-worker

composer require topthink/think-worker=2.0.*

直接安裝workman

composer require workerman/workerman

(2)我們先來看think-worker 的程式碼

  • config/worker_server.php

  • 先來個伺服器廣播訊息的範例,每10秒鐘定時廣播一則訊息

'onWorkerStart'  => function ($worker) {
    \Workerman\Lib\Timer::add(10, function()use($worker){
        // 遍历当前进程所有的客户端连接,发送自定义消息
        foreach($worker->connections as $connection){
            $send['name'] = '系统信息';
            $send['content'] = '这是一个定时任务信息';
            $send['time'] = time();
            $connection->send(json_encode($send));
        }
    });
}

但是在onMessage 時,我們取得不到$worker 對象,所以無法廣播訊息。

'onMessage'      => function ($connection, $data) {
    $origin = json_decode($data,true);
    $send['name'] = '广播数据';
    $send['content'] = $origin['content'];
    $message = json_encode($send);

    foreach($worker->connections as $connection)
    {
        $connection->send($message);
    }
}

嘗試了各種方法,似乎都不行

'onMessage'      => function ($connection, $data)use($worker) {
    // 这样是获取不到 $worker 对象的
    // ...省略代码
}

所以只能拋棄thinkphp 給我們封裝的think-worker 框架,得自己寫,(或修改框架內部程式碼)

修改框架內部的程式碼:/vendor/topthink/think-worker/src/command/Server.php,主要是把onMessage 方法自己加進去

use()就是把外部變數傳遞到函數內部使用,或是使用global $worker

$worker = new Worker($socket, $context);

$worker->onMessage = function ($connection, $data)use($worker) {
    $origin = json_decode($data,true);
    $send['name'] = '广播数据';
    $send['content'] = $origin['content'];
    $send['uid'] = $connection->uid;
    $message = json_encode($send);
    foreach($worker->connections as $connection)
    {
        $connection->send($message);
    }
};

這樣,我們就能夠取得$worker 物件了

$worker->onMessage = function ($connection, $data)use($worker) { ... }

#( 3)$connection 綁定uid

其實你早都已經看出,$worker->connections 獲取到的是當前所有用戶的連接,connections 即為其中一個鏈接。

記錄websocket連線時間:

$worker->onConnect = function ($connection) {
    $connection->login_time = time();
};

取得websocket連線時間:

$worker->onMessage = function ($connection, $data)use($worker) {
    $login_time = $connection->login_time;
};

由此可以看出,我們可以把資料綁定到$connection 連線的一個屬性,例如:

$connection->uid = $uid;

當JavaScript端在連接websocket伺服器成功後,也就是把自己的uid 立刻發送服務端綁定:

$worker->onMessage = function ($connection, $data)use($worker) {
    $origin = json_decode($data,true);
    if(array_key_exists('bind',$origin)){
        $connection->uid = $origin['uid'];
    }
};

(4)單播傳送訊息,即自訂發送

$worker->onMessage = function ($connection, $data)use($worker) {
    $origin = json_decode($data,true);
    $sendTo = $origin['sendto']; // 需要发送的对方的uid
    $content = $origin['content']; // 需要发送到对方的内容
    foreach($worker->connections as $connection)
    {
        if( $connection->uid == $sendTo){
            $connection->send($content);
        }
    }
};

到此,已經完成基於workman 的自訂物件發送訊息。

由於該php檔案存放在composer中,只需要把該檔案複製出來,放到application/command,修改命名空間,即可儲存到自己的專案中

(5)比較swoole

1、workman可以在windows系統中執行,swoole則不能。

2、workman:$worker->connections取得所有連接,$connection->id取得自己的連接id;swoole:$server->connections取得所有連接,$connection->fd取得自己的連接id。

3、workman啟動時執行 onWorkerStart 方法,可以把定時器寫入到裡面;swoole 使用 WorkerStart 啟動計時器。

僅僅於聊天室或計時器而言,workman 還是比較方便的。

更多ThinkPHP相關技術文章,請造訪ThinkPHP使用教學欄位進行學習!

以上是使用 Workman 做一個聊天室的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn