特别注意:
[1]客户端的事件及数据全部由Gateway转发给BusinessWorker处理,BusinessWorker默认调用Events.php中的onConnect onMessage onClose处理业务逻辑。
[2]通过GatewayClient发送的数据不会经过Event.php,而是直接经由Gateway进程转发给客户端。GatewayClient无法接收客户端发来的数据。
第一步准备好最新的TP5和GatewayWorker
https://www.workerman.net/download //GatewayWorker下载地址
http://www.thinkphp.cn/down/1278.html //TP5下载地址
下载完成解压到本地。
GatewayWorker直接放到TP5根目录下就行
下载GatewayClient
https://github.com/walkor/GatewayClient //下载地址
因为是最新版的GatewayWorker直接下载最新版的GatewayClient就行,然后解压里面的Gateway.php
放到TP5下的E:\WWW\tp5\thinkphp\library\think这是我的目录,前面要改成自己的目录,注意命名空间。
第二步修改内容
修改刚刚解压的Gateway.php里的内容
namespace GatewayClient; 修改成
namespace think;
把 注册中心地址改成 public static $registerAddress = '127.0.0.1:9500';
记住后面端口一定要和GatewayWorker\Applications\YourApp下的start_businessworker.php,start_gateway.php,start_register.php保持一致就行,我就改成了9500
start_gateway.php文件,这个文件是默认的文件,默认协议是text协议
修改GatewayWorker\Applications\YourApp下的start_gateway.php
$gateway = new Gateway("tcp://0.0.0.0:8282");
修改成
$gateway = new Gateway("websocket://0.0.0.0:8282");
第三步创建控制器
话不多说直接贴上控制器代码
<?php
namespace app\base\controller\v1;
use app\base\controller\v1\Base as Base;
use think\Controller;
use think\Gateway;
class WorkerMan extends Controller
{
public function bind() {
$uid = 3;
$client_id = input('client_id');
$gateway = new Gateway();
$gateway->bindUid($client_id, $uid);
$message = '绑定成功' . $uid . '-' . $client_id;
$gateway->sendToUid($uid,$message);
}
public function message() {
$to_uid = input('uid');
$message = input('msg');
$gateway = new Gateway();
$data['msg'] = $message;
$data['from_uid'] = 3;
$data['to_uid'] = $to_uid;
// $gateway->sendToUid($to_uid, json_encode($data)); //发给对方
$gateway->sendToAll(json_encode($data));//发给所有人
// $gateway->sendToUid($data['from_uid'], json_encode($data)); //发给自己
echo json_encode($data);
}
}
新建index.html,代码如下
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>chatroom</title>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"/></script>
<script type="text/javascript">
// 打开一个 web socket
var ws = new WebSocket("ws://8.131.90.126:8282");
// var ws = new WebSocket("ws://8.140.115.226:2000");
ws.onopen = function ()
{
// var name = prompt("请输入昵称","");
// if(name){
// $("b").text(name);
// }
console.log('上线');
};
ws.onerror=function(e){
console.log(e);
}
ws.onclose=function(e){
console.log(e);
console.log('下线');
}
ws.onmessage = function (evt)
{
var received_msg = evt.data;
// console.log("数据已接收..." + received_msg);
if(isJsonString(received_msg)){
var jmsg = JSON.parse(received_msg);
console.log(jmsg);
switch (jmsg.type) {
case 'init':
var bind = '{"type":"bind","from_id":"' + 1 + '","to_id":"' + 2 + '"}';
ws.send(bind);
var online = '{"type":"online","from_id":"' + 1 + '","to_id":"' + 2 + '"}';
ws.send(online);
break;
// case 'online':
// if (jmsg.status == 1) {
// var say = '{"type":"say","from_id":"' + 1 + '","to_id":"' + 2 + '"}';
// ws.send(say);
// // set_online_status(true);
// } else {
// // set_online_status(false);
// }
// return;
// case "say":
// // To_receive_message('txt',message);
// // $(".chat-content").scrollTop(3000);
// return;
}
}
}
function isJsonString(str) {
try {
if (typeof JSON.parse(str) == "object") {
return true;
}
} catch (e) {
}
return false;
}
function send() {
var message = document.getElementById('text').value;
ws.send(message);
}
</script>
</head>
<body>
<ul id="message">
</ul>
<div>
<label>昵称:<b></b></label><br/>
<input name="msg" value="" size="50">
<button type="button" id="send" >发送</button>
</div>
<!-- <script>
//后台交互式
$(function () {
$url = "http://8.131.90.126:8083/public/base/v1/message"
$("#send").click(function () {
var name = $("b").html();
var msg = $('input[name="msg"]').val();
$.post($url, {from_uid: 2, msg: msg,to_uid:1}, function (data) {
console.log(data);
$('input[name="msg"]').val('');
});
});
});
</script> -->
<script type="text/javascript">
//websocket交互式
$("#send").click(function () {
var msg = $('input[name="msg"]').val();
// $.post($url, {from_uid: 2, msg: msg,to_uid:1}, function (data) {
var say = '{"type":"say","from_id":"' + 1 + '","to_id":"' + 2 + '","content":"'+msg+'"}';
ws.send(say);
// $('input[name="msg"]').val('');
});
</script>
</body>
</html>
然后在本地服务器开启GatewayWorker
windows双击打开GatewayWorker\start_for_win.bat
linux在GatewayWorker目录下执行php start.php start 运行(注意安全组需要放行端口 目前我放行的8282 9500 )
打开浏览器输入网址加上Uid
出现绑定成功说明已经成功了,然后第一个输入框输入对应id就能和这个id的人对话了
Eents.php示例
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* 用于检测业务代码死循环或者长时间阻塞等问题
* 如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行php start.php reload
* 然后观察一段时间workerman.log看是否有process_timeout异常
*/
//declare(ticks=1);
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, json_encode(['type'=>'init','client_id'=>$client_id]));
// 向所有人发送
// Gateway::sendToAll("$client_id login\r\n");
}
/**
* 当客户端发来消息时触发
* GatewayWorker建议不做任何业务逻辑,onMessage留空即可
* @param int $client_id 连接id
* @param mixed $message 具体消息
*/
public static function onMessage($client_id, $message)
{
//示例: $message = '{"type":"send_to_uid","uid":"xxxxx", "message":"...."}'
$message_data = json_decode($message,true);
if ($message_data){
//TODO 方便区分信息传递类型
$type = $message_data['type'];
// 发送人ID,此处为数据库中管理员的ID
$from_id = $message_data['from_id'];
// 接收人ID
$to_id = isset($message_data['to_id'])?$message_data['to_id']:0;
switch ($type){
case 'bind':
//将client_id与uid绑定,用来唯一确定一个客户端用户或者设备
Gateway::bindUid($client_id,$from_id);
$_SESSION['gateway-worker_'.$client_id] = $from_id;
return;
case 'online':
//判断接收人是否在线
$onlineStatusForTo_id = Gateway::isUidOnline($to_id);
$onlineStatusForFrom_id = Gateway::isUidOnline($from_id);
Gateway::sendToUid($from_id, json_encode(['type'=>'online','to_id'=>$to_id,'status'=>$onlineStatusForTo_id]));
Gateway::sendToUid($to_id, json_encode(['type'=>'online','to_id'=>$from_id,'status'=>$onlineStatusForFrom_id]));
return;
case 'say':
//发送文字
$text = nl2br(htmlspecialchars($message_data['content']));
$sayData = [
'type' => 'say',
'content' => $text,
'from_id' => $from_id,
'to_id' => $to_id
];
if (Gateway::isUidOnline($to_id)){
$sayData['is_read'] = 1;
Gateway::sendToUid($to_id, json_encode($sayData));
}else{
$sayData['is_read'] = 0;
}
Gateway::sendToUid($from_id,json_encode($sayData));
return;
}
}else{
return;
}
}
/**
* 当用户断开连接时触发
* @param int $client_id 连接id
*/
public static function onClose($client_id)
{
$uid = $_SESSION['gateway-worker_'.$client_id];
// 向所有人发送
$send_msg = json_encode(['type'=>'online','to_id'=>$uid,'status'=>0,'content'=>'对方掉线了!']);
$_SESSION['gateway-worker_'.$client_id] = null;
// Gateway::sendToAll($send_msg);
}
}