聊天室主要用到GatewayWorker ,它是对workerman的进一步封装
GatewayWorker基于Workerman开发的一个项目框架,用于快速开发TCP长连接应用,例如app推送服务端、即时IM服务端、物联网、智能家居等等。
1. 安装环境
1.1 首先下载框架
composer require workerman/gateway-worker
然后下载 demo
GatewayWorker 有分为linux版本 和 windows 版本。
2个版本主要不同是 :
1. 启动文件不同 , windows 用 bat 文件启动 ,linux 直接 php start.php start 启动
以后台进程的形式开启
php start.php start -d
2. 某些文件夹的命名不一样
由于我是windows开发,运行在linux服务器 。这里我这里直接选择linux版本的 , 然后启动文件我复制windows版的bat启动文件
我用的是tp5 我把启动文件放到根目录 调整bat里面的路径
php application\push\start_register.php application\push\start_gateway.php application\push\start_businessworker.php
pause
1.2 第二步
将Applications/Yourapp复制到tp5目录application中,并更改名字为push(这里随意)
|--push
|--Events.php
|--start_businessworker.php
|--start_gateway.php
|--start_register.php
将start.php复制到tp5根目录下,并更改start.php最后的foreach路径 我的目录是application/push
foreach(glob(__DIR__.'/application/push/start*.php') as $start_file)
{
require_once $start_file;
}
根目录中启动 php start.php start (linux) ,windows 直接 双击 bat文件 start_for_win
2. 如何使用gatewayworker
一般即时通讯的业务逻辑 会写在在 Events.php里
use \GatewayWorker\Lib\Gateway;
/**
* 主逻辑
* 主要是处理 onConnect onMessage onClose 三个方法
* onConnect 和 onClose 如果不需要可以不用实现并删除
*/
class Events
{
/**
* 当客户端连接时触发
* 如果业务不需此回调可以删除onConnect
*
* @param int $client_id 连接id
*/
public static function onConnect($client_id)
{
// 向当前client_id发送数据
Gateway::sendToClient($client_id, "Hello $client_id\r\n");
// 向所有人发送
Gateway::sendToAll("$client_id login\r\n");
}
/**
* 当客户端发来消息时触发
* @param int $client_id 连接id
* @param mixed $message 具体消息
*/
public static function onMessage($client_id, $message)
{
// 向所有人发送
Gateway::sendToAll("$client_id said $message\r\n");
}
}
点对点的通讯 就是类似下图
2.1 常用函数和思路
1. bindUid 跟客户端传入的 uid 绑定
2. isUidOnline 判断该客户端id 是否在线
3. sendToUid 发消息给指定客户端id
4. sendToAll 向所有连接到 该socket服务器的客户端 发送消息
3. 简单例子
服务器端:
use \GatewayWorker\Lib\Gateway;
/**
* 主逻辑
* 主要是处理 onConnect onMessage onClose 三个方法
* onConnect 和 onClose 如果不需要可以不用实现并删除
*/
class Events
{
/**
* 当客户端连接时触发
* 如果业务不需此回调可以删除onConnect
*
* @param int $client_id 连接id
*/
public static function onConnect($client_id)
{
// 向当前client_id发送数据
//Gateway::sendToClient($client_id, "Hello $client_id\r\n");
// 向所有人发送
//Gateway::sendToAll("$client_id login\r\n");
Gateway::sendToClient($client_id, json_encode(["type"=>'init','client_id'=>$client_id]));
}
/**
* 当客户端发来消息时触发
* @param int $client_id 连接id
* @param mixed $message 具体消息
*/
public static function onMessage($client_id, $message)
{
// 向所有人发送
$message_data = json_decode($message,true);
if(!$message_data){
return;
}
switch($message_data['type']){
case 'bind':
//$datas = ['type'=>'text','client_id'=>$client_id,'data'=>$message_data['data']];
//echo $message_data['fromid'];
Gateway::bindUid($client_id, $message_data['fromid']);
break;
case 'talk':
$datas = [
'type'=>'text',
'client_id'=>$client_id,
'data'=>htmlspecialchars($message_data['data']),
'fromid'=>$message_data['fromid'],
'toid'=>$message_data['toid'],
'timestamp'=>time()
];
if(Gateway::isUidOnline($message_data['toid'])){
$datas['isread']=1;
}else{
$datas['isread']=0;
}
Gateway::sendToUid($message_data['toid'],json_encode($datas));
//保存数据
$talkurl='http://www.superchat.com/index/Chat';
$params =['fromid'=>$message_data['fromid'],'toid'=>$message_data['toid'],'content'=>htmlspecialchars($message_data['data']),'time'=>time(),'isread'=>$datas['isread'],'type'=>1];
self::curl_https($talkurl,$params,1);
//同步数据
Gateway::sendToUid($message_data['fromid'],json_encode(['type'=>'update_message','client_id'=>$client_id,'fromid'=>$message_data['fromid'],'toid'=>$message_data['toid'],'timestamp'=>time()]));
break;
case 'online':
$datas = ['type'=>'online','fromid'=>$message_data['fromid'],'toid'=>$message_data['toid']];
$datas['isonline'] = 0;
Gateway::sendToUid($message_data['fromid'],json_encode($datas));
break;
case 'images':
$datas = [
'type'=>'images',
'fromid'=>$message_data['fromid'],
'toid'=>$message_data['toid'],
'data'=>$message_data['data'],
'time'=>time()
];
Gateway::sendToUid($message_data['toid'],json_encode($datas));
break;
default:
}
//echo '123123';
}
}
客户端:
<script>
var API = "http://www.superchat.com/index/Chat/";
var fromid ={$fromid};
var ws = new WebSocket("ws://127.0.0.1:8282");
ws.onmessage = function(e) {
var Respoonse = JSON.parse(e.data);
console.log(Respoonse);
switch(Respoonse.type){
case 'init':
//console.log(Respoonse);
var bindmesaage = '{"type":"bind","fromid":"'+fromid+'"}';
ws.send(bindmesaage);
message_list();
break;
case 'text':
$(".fui-content").html('');
message_list();
break;
case 'images':
$(".fui-content").html('');
message_list();
break;
case 'update_message':
$(".fui-content").html('');
message_list();
break;
}
}
</script>
根据 onmessage 返回的json内容 ,对UI 做出相应的更改