>[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)
只保留以下三个文件然后粘贴到项目根目录下,跳过重复文件即可
.![](https://box.kancloud.cn/ca40dc335da755872648f1675d5ce3ce_917x240.png)
>[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
```
* 开启成功截图:
![](https://box.kancloud.cn/8239a7ecf1177197ce80d4c9792e20d3_787x354.png)
>[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配置码云版本控制器
- 聊天系统功能的实现
- 用户登录
- 用户注册
- 用户主页
- 修改个性签名
- 上传头像
- 修改用户资料
- 在线状态切换
- 查找功能
- 添加好友
- 查找/添加好友
- 消息盒子(一)
- 消息盒子(二)
- 添加群组
- 好友请求
- 创建群组
- 添加群组
- 管理群请求
- 获取群成员
- 好友聊天
- 发送图片
- 发送文件
- 用户中心
- 用户资料/修改密码
- 退出
- 右键菜单
- 好友右键菜单
- 查看资料
- 历史纪录
- 删除好友
- 屏蔽/接受消息
- 举报好友
- 群组右键菜单
- 查看群资料
- 主面板右键菜单
- 好友分组右键菜单
- 数据表大全
- 全国各省市区代码数据库表
- 项目源码