>[info]后端 Laravel 需要調用 GatewayClient API 通知 GatewayWorker 綁定 client_id,首先在 Laravel 項目(聊天室)根目錄下運行 Composer 命令來安裝:
```
composer require workerman/gateway-worker
composer require workerman/gatewayclient
```
>[info][下載Linux版本的demo](http://www.workerman.net/download/GatewayWorker.zip)
只保留以下三個文件然后粘貼到項目根目錄下,跳過重復文件即可
.
>[info]將Applications下的YourApp改為GeChat;
修改Applications/GeChat/下的start_businessworker.php里的worker名稱和服務注冊地址
```
// worker名稱
$worker->name = 'GeChatBusinessWorker';
// bussinessWorker進程數量
$worker->count = 4;
// 服務注冊地址
$worker->registerAddress = '127.0.0.1:1314';
```
>[info]修改Applications/GeChat/下的start_gateway.php,云服務器本機IP需改為:0.0.0.0;
```
$gateway = new Gateway('websocket://0.0.0.0:5210');
// gateway名稱,status方便查看
$gateway->name = 'GeChatGateway';
// gateway進程數
$gateway->count = 4;
// 本機ip,分布式部署時使用內網ip
$gateway->lanIp = '0.0.0.0';
// 內部通訊起始端口,假如$gateway->count=4,起始端口為4000
// 則一般會使用4000 4001 4002 4003 4個端口作為內部通訊端口
$gateway->startPort = 4000;
// 服務注冊地址
$gateway->registerAddress = '127.0.0.1:1314';
```
>[info]修改Applications/GeChat/下的start_register.php里的端口號:
```
// register 必須是text協議
$register = new Register('text://0.0.0.0:1314');
```
>[info]隨后進入項目根目錄運行命令:
```
php start.php start -d
```
* 開啟成功截圖:

>[info]然后在需要調用 GatewayClient 接口的文件里,引用命名空間:
```// GatewayClient 3.0.0版本以后加了命名空間
use GatewayClient\Gateway;
```
>[info]并設置 Gateway::$registerAddress 屬性,告知 GatewayClient 與哪個 GatewayWorker (集群)通訊。方便起見,我把它放在了 Laravel 控制器的 __construct() 方法里:
```
public function __construct()
{
Gateway::$registerAddress = '127.0.0.1:1314';
}
```
>[danger] 這個屬性的設置值必須與前面啟動的 Gateway 進程和 BusinessWorker 進程的 registerAddress 屬性值一致,其中的 1314端口是由 Register 服務進程監聽的,用于 Gateway 進程和 BusinessWorker 進程內部通訊。
>[info]客戶端web socket 連接Gateway Worker代碼:
```
socket = new WebSocket('ws://192.168.10.10:5210');
```
>[info]比如Events.php下的onConnect()方法,將Gateway Worker綁定的client_id發送給客戶端,客戶端收到后繼續將client_id發送給Laravel框架完成初始化。客戶端鏈接到Gateway Worker后觸發:
>[warning] Events.php只保留一個onConnect()方法,并且僅在用戶登錄成功后渲染主頁面時使用;
```
public static function onConnect($client_id) {
Gateway::sendToClient($client_id, json_encode(array(
'type' => 'init',
'client_id' => $client_id
)));
}
```
>[info]客戶端收到init指令后觸發:
```
socket = new WebSocket('ws://192.168.10.10:5210');
//連接成功時觸發
socket.onopen = function(){
// 登錄
console.log("websocket握手成功!");
};
//監聽收到的消息
socket.onmessage = function(e) {
var data = JSON.parse(e.data),
type = data.type || '',
message = data.data || '';
switch (type) {
case 'init':
var client_id = data.client_id || '';
$.post(gechat_url_init,{
type: 'init',
client_id : client_id,
id : uid ,
username : uname,
avatar : avatar,
sign : sign
}, function (res) {
},'json');
console.log('已發送初始化json');
break;
```
>[info]Laravel框架收到post過來的client_id后進行綁定,然后把該用戶的好友,群組,離線消息發送給客戶端,繼而完成初始化;
```
public function init(Request $request)
{
$message = $request->all();
$message_type = $message['type'];
switch ($message_type) {
case 'init' :
$uid = $request->session()->get('GEEK');
$client_id = $message['client_id'];
Gateway::bindUid($client_id, $uid); // uid 與 room_id 已經從 Laravel session里獲取
Gateway::sendToUid($uid, json_encode(array(
'type' => 'notice',
'content' => 'init success !',
)));
$request->session()->put([
'client_id' => $client_id,
'username' => $message['username'],
'avatar' => $message['avatar'],
'sign' => $message['sign']
]); // Laravel 負責
Gateway::setSession($client_id, [ // GatewayWorker 負責
'id' => $uid,
'username' => $message['username'],
'avatar' => $message['avatar'],
'sign' => $message['sign']
]);
/*$_SESSION['uid'] = $uid;
$_SESSION['username'] = $message['username'];
$_SESSION['avatar'] = $message['avatar'];
$_SESSION['sign'] = $message['sign'];*/
//查詢有無需要推送的離線信息
$resMsg = ChatLog::where([
['to_id','=',$uid],
['need_send','=',1]
])->get();
//var_export($resMsg);
if (!empty($resMsg)) {
foreach ($resMsg as $vo) {
$log_message = [
'type' => 'logMessage',
'data' => [
'username' => $vo->from_name,
'avatar' => $vo->from_avatar,
'id' => $vo->from_id,
'type' => $vo->type,
'content' => htmlspecialchars($vo->content),
'timestamp' => strtotime($vo->created_at)*1000,
]
];
Gateway::sendToUid($uid, json_encode($log_message));
//設置推送狀態為已經推送
}
ChatLog::where('to_id','=',$uid)->update(['need_send' => 0]);
}
//獲取它的所有朋友的id
$friendsAll = \App\Http\Models\GeFriend::where([
['friend_id', '=', $uid],
])->pluck('user_id');
if (!empty($friendsAll)) {
foreach ($friendsAll as $vo) {
$user_client_id = Gateway::getClientIdByUid($vo);
if (!empty($user_client_id)) {
$online_message = [
'type' => 'online',
'id' => $uid,
];
Gateway::sendToUid($vo, json_encode($online_message));
}
}
}
$ret = GeChatGroup::where('user_id','=',$uid)->get();
if (!empty($ret)) {
foreach ($ret as $key => $vo) {
Gateway::joinGroup($client_id, $vo->group_id); //將登錄用戶加入群組
}
}
unset($ret);
//設置用戶為登錄狀態
$post = GeUser::where('id','=',$uid)->first();
$post -> status = 1;
$post -> save();
return 0;
break;
```
>[info]后續的所有聊天消息都直接 get/post 到 Laravel 控制器里統一處理,上面的初始化代碼沒看懂沒有關系,你只要把Gateway Worker配置好并且成功啟動就可以了,我會在用戶主頁一節繼續對上述代碼進行講解;
- 序言
- 開發必讀
- GeChat系統原理
- GeChat系統整體構建
- Laravel安裝配置
- GatewayWorker的結合
- Layim的結合
- PhpStorm配置碼云版本控制器
- 聊天系統功能的實現
- 用戶登錄
- 用戶注冊
- 用戶主頁
- 修改個性簽名
- 上傳頭像
- 修改用戶資料
- 在線狀態切換
- 查找功能
- 添加好友
- 查找/添加好友
- 消息盒子(一)
- 消息盒子(二)
- 添加群組
- 好友請求
- 創建群組
- 添加群組
- 管理群請求
- 獲取群成員
- 好友聊天
- 發送圖片
- 發送文件
- 用戶中心
- 用戶資料/修改密碼
- 退出
- 右鍵菜單
- 好友右鍵菜單
- 查看資料
- 歷史紀錄
- 刪除好友
- 屏蔽/接受消息
- 舉報好友
- 群組右鍵菜單
- 查看群資料
- 主面板右鍵菜單
- 好友分組右鍵菜單
- 數據表大全
- 全國各省市區代碼數據庫表
- 項目源碼