使用 Workman 做一個聊天室

使用 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) {     WorkermanLibTimer::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使用教程欄目進行學習!

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享