赞
踩
composer require workerman/gateway-worker-for-win
composer require workerman/workerman-for-win
2.安装完成后 在vendor文件夹里
3.代码
在application目录下,创建一个应用模块,模块名称为gatewayapp,其目录结构如下
controller/GwEvents.php文件,该文件是业务逻辑处理类,实际开发中,只需要关注这个文件即可
<?php namespace app\gatewayapp\controller; use GatewayWorker\Lib\Gateway; /** * 主逻辑 * 主要是处理 onConnect onMessage onClose 三个方法 * onConnect 和 onClose 如果不需要可以不用实现并删除 */ class GwEvents { /** * 当客户端连接时触发 * 如果业务不需此回调可以删除onConnect * * @param int $client_id 连接id */ public static function onConnect($client_id) { //当客户端连接时,向当前的client_id发送当前的连接id //控制台会报错 发json Gateway::sendToClient($client_id, json_encode(['message_type'=>'init','client_id'=>$client_id])); // 向所有人发送 //Gateway::sendToAll(sprintf('用户 %s 已登录!',$client_id)); } /** * 当客户端发来消息时触发 * @param int $client_id 连接id * @param mixed $message 具体消息 */ public static function onMessage($client_id, $message) { //Gateway::sendToClient($client_id, sprintf('hi %s',$client_id)); $message = json_decode($message, true); $message_type = $message['type']; switch($message_type) { //客户端发来的消息类型是login, case 'login': // uid $uid = $message['formid']; // 设置session $_SESSION = [ 'id' => $uid, ]; // 将当前链接id与uid绑定 Gateway::bindUid($client_id, $uid); return; break; //客户端发送过来聊天消息,由服务器发送给他想发送的那个人,也就是toid case 'chatMessage': $content = $message['data']['mine']['data']; $formid = $message['data']['mine']['formid']; $to_id = $message['data']['to']['toid']; // $uid = $_SESSION['id']; $chat_message = [ 'message_type' => 'chatMessage',//发送类型 'content'=>htmlspecialchars($content),//发送内容 'formid'=>$formid,//发送者的id 'toid'=>$to_id//接收者的id ]; //发送给toid return Gateway::sendToUid($to_id, json_encode($chat_message)); break; // case 'hide': // case 'online': // $status_message = [ // 'message_type' => $message_type, // 'id' => $_SESSION['id'], // ]; // $_SESSION['online'] = $message_type; // Gateway::sendToAll(json_encode($status_message)); // return; // break; case 'ping': return; default: echo "unknown message $message" . PHP_EOL; } } /** * 当用户断开连接时触发 * @param int $client_id 连接id */ public static function onClose($client_id) { // 向所有人发送 GateWay::sendToAll(sprintf('用户 %s 已退出!',$client_id)); } }
controller/Index.php文件
<?php
namespace app\gatewayapp\controller;
use think\Controller;
class Index extends Controller {
public function index() {
$formid = input('formid');
$toid = input('toid');
$this->assign('formid',$formid);
$this->assign('toid',$toid);
return $this->fetch();
}
}
view/index/index.html视图文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>WebSocket示例</title> <script src="/static/jquery/jquery-3.1.1.min.js"></script> </head> <body> <div> <input type="text" name="msg" id="aaa"> <input id="sendMsg" type="button" value="发送"> </div> <script type="text/javascript"> var formid = {$formid}; var toid = {$toid}; var webSocket = null; initSocket(); function initSocket() { if (!"WebSocket" in window) { console.log("您的浏览器不支持 WebSocket!"); return; } webSocket = new WebSocket("ws://"+document.domain+":8283"); webSocket.onopen = handleSend; webSocket.onmessage = handleMessage; webSocket.onclose = handleClose; webSocket.onerror = handleError; } // 向服务器端发送数据 function handleSend() { } // 处理服务器端发送过来的数据 function handleMessage(evt) { console.log(evt.data); //把json数据转成js对象 var received_msg = eval("("+evt.data+")"); // console.log(received_msg); switch(received_msg['message_type']) { //服务端ping客户端 case 'ping': webSocket.send('{"type":"ping"}'); // 接收的消息类型如果是init,再将页面上的formid发给服务器 case 'init': //console.log(received_msg['id']+"登录成功"); var bild = '{"type":"login","formid":"'+formid+'"}'; webSocket.send(bild); break; // 检测聊天数据 case'chatMessage': console.log(received_msg['content']); break; // 离线消息推送 case 'logMessage': setTimeout(function(){}, 1000); break; // 用户退出 更新用户列表 case 'logout': break; } } // 处理连接关闭事件 function handleClose() { console.log("连接已关闭..."); } // 处理WebSocket错误 function handleError() { console.log("WebSocketError!"); } //取到input里的聊天数据,发送给服务器 $('#sendMsg').on('click',function() { var content = $('input[name=msg]').val(); var res = new Array(); res['mine'] = { data: content, formid:formid, }; res['to'] = { toid:toid }; var mine = JSON.stringify(res.mine); var to = JSON.stringify(res.to); var chat_data = '{"type":"chatMessage","data":{"mine":' + mine + ', "to":' + to + '}}'; console.log(chat_data); webSocket.send(chat_data); }) </script> </body> </html>
run/start_register.php文件
use GatewayWorker\Register; use Workerman\Worker; $registerInstance = new GwRegister(); call_user_func_array(array($registerInstance,'index'),array()); class GwRegister { public function __construct() { require_once dirname(__FILE__) . '/../../../vendor/autoload.php'; include_once dirname(__FILE__).'/../const.php'; } public function index() { // register 必须是text协议 $registerAddress = sprintf('text://%s',GW_REGISTER_PROTOCOL); $register = new Register($registerAddress); // 如果不是在根目录启动,则运行runAll方法 if(!defined('GLOBAL_START')) { Worker::runAll(); } } }
run/start_gateway.php文件
use Workerman\Worker; use GatewayWorker\Gateway; use Workerman\Autoloader; $gatewayInstance = new GwGateway(); call_user_func_array(array($gatewayInstance,'index'),array()); class GwGateway { private $gatewayAddress; public function __construct() { require_once dirname(__FILE__) . '/../../../vendor/autoload.php'; include_once dirname(__FILE__).'/../const.php'; // gateway 进程,这里使用websocket协议 $this->gatewayAddress = sprintf('websocket://%s',GW_GATEWAY_ADDRESS); } public function index() { $gateway = new Gateway($this->gatewayAddress); // 设置名称,方便status时查看 $gateway->name = GW_GATEWAY_NAME; // 设置进程数,gateway进程数建议与cpu核数相同 $gateway->count = GW_GATEWAY_COUNT; // 本机ip,分布式部署时请设置成内网ip(非127.0.0.1) $gateway->lanIp = GW_LOCAL_HOST_IP; // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000 // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口 $gateway->startPort = GW_GATEWAY_START_PORT; // 服务注册地址 $gateway->registerAddress = GW_REGISTER_ADDRESS; // 心跳间隔,单位:秒,0 表示不发送心跳检测 $gateway->pingInterval = GW_GATEWAY_PING_INTERVAL; // 心跳数据 $gateway->pingData = '{"type":"ping"}'; /* // 当客户端连接上来时,设置连接的onWebSocketConnect,即在websocket握手时的回调 $gateway->onConnect = function($connection) { $connection->onWebSocketConnect = function($connection , $http_header) { // 可以在这里判断连接来源是否合法,不合法就关掉连接 // $_SERVER['HTTP_ORIGIN']标识来自哪个站点的页面发起的websocket链接 if($_SERVER['HTTP_ORIGIN'] != 'http://kedou.workerman.net') { $connection->close(); } // onWebSocketConnect 里面$_GET $_SERVER是可用的 // var_dump($_GET, $_SERVER); }; }; */ // 如果不是在根目录启动,则运行runAll方法 if(!defined('GLOBAL_START')) { Worker::runAll(); } } }
run/start_businessworker.php文件
use Workerman\Worker; use GatewayWorker\BusinessWorker; use Workerman\Autoloader; $businessInstance = new GwBusinessWorker(); call_user_func_array(array($businessInstance,'index'),array()); class GwBusinessWorker { public function __construct() { require_once dirname(__FILE__) . '/../../../vendor/autoload.php'; include_once dirname(__FILE__).'/../const.php'; } public function index() { // bussinessWorker 进程 $worker = new BusinessWorker(); // worker名称 $worker->name = GW_WORKER_NAME; // bussinessWorker进程数量 $worker->count = GW_BUSINESS_WORKER_COUNT; // 服务注册地址 $worker->registerAddress = GW_REGISTER_ADDRESS; //设置处理业务的类,此处制定Events的命名空间 $worker->eventHandler = GW_BUSINESS_EVENT_HANDLER; // 如果不是在根目录启动,则运行runAll方法 if(!defined('GLOBAL_START')) { Worker::runAll(); } } }
const.php常量定义文件,根据需要,修改相关常量对应的值。
// 注册协议 define('GW_REGISTER_PROTOCOL','0.0.0.0:1236'); // 注册地址 define('GW_REGISTER_ADDRESS','127.0.0.1:1236'); // 网关地址 define('GW_GATEWAY_ADDRESS','0.0.0.0:8283'); // 网关起始端口 define('GW_GATEWAY_START_PORT','2900'); // 心跳检测间隔,单位:秒,0 表示不发送心跳检测 define('GW_GATEWAY_PING_INTERVAL',10); // 本机ip,分布式部署时请设置成内网ip(非127.0.0.1) define('GW_LOCAL_HOST_IP','127.0.0.1'); // 网关名称 define('GW_GATEWAY_NAME','Gateway001'); // worker进程名称 define('GW_WORKER_NAME','BusinessWorker001'); // Gateway进程数量,建议与CPU核数相同 define('GW_GATEWAY_COUNT',2); // BusinessWorker进程数量,建议设置为CPU核数的1倍-3倍 define('GW_BUSINESS_WORKER_COUNT',6); // Business业务处理类,可以带命名空间 define('GW_BUSINESS_EVENT_HANDLER','app\gatewayapp\controller\GwEvents');
start_for_win.bat启动文件
php run\start_register.php run\start_gateway.php run\start_businessworker.php
pause
双击start_for_win.bat文件,启动websocket服务,启动成功后的界面如下:
打开浏览器,定位到视图url,可以多开几个浏览器,然后切换到任何一个浏览器的控制台,效果如下
撒花,完结
转载https://blog.csdn.net/tdcqfyl/article/details/81170420#commentBox
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。