zoukankan      html  css  js  c++  java
  • thinkphp5整合 gatewaywork实现聊天

    1:将下载的gatewaywork下的vendor  下的workman文件夹,整个复制到tp5下的vendor目录下

    2:tp5applicationpush   新键push文件夹,将下载的gatewaywork下的ApplicationsYourApp里面的文件拷贝到push下

    3:修改:start_businessworker.php

    <?php
    /**
    *
    * @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
    */
    use WorkermanWorker;
    use WorkermanWebServer;
    use GatewayWorkerGateway;
    use GatewayWorkerBusinessWorker;
    use WorkermanAutoloader;

    // 自动加载类
    require_once __DIR__ . '/../../vendor/autoload.php';

    // bussinessWorker 进程
    $worker = new BusinessWorker();
    // worker名称
    $worker->name = 'YourAppBusinessWorker';
    // bussinessWorker进程数量
    $worker->count = 4;
    // 服务注册地址
    $worker->registerAddress = '127.0.0.1:1238';
    //设置处理业务的类,此处制定Events的命名空间
    //这里设置,聊天的类的方法,其实就是吧events放到了index模块下,指定一下而已,也可以修改到本push下面,自己看着办
    $worker->eventHandler = 'appindexcontrollerEvents';
    // 如果不是在根目录启动,则运行runAll方法
    if(!defined('GLOBAL_START'))
    {
    Worker::runAll();
    }

     4:修改start_gateway.php

    <?php
    use WorkermanWorker;
    use WorkermanWebServer;
    use GatewayWorkerGateway;
    use GatewayWorkerBusinessWorker;
    use WorkermanAutoloader;

    // 自动加载类
    require_once __DIR__ . '/../../vendor/autoload.php';

    // gateway 进程,这里使用Text协议,可以用telnet测试
    // 这里聊天使用websocket协议,如果需要用tcp连接,修改websocket为tcp即可
    $gateway = new Gateway("Websocket://0.0.0.0:8282");
    // gateway名称,status方便查看
    $gateway->name = 'YourAppGateway';
    // gateway进程数
    $gateway->count = 4;
    // 本机ip,分布式部署时使用内网ip
    $gateway->lanIp = '127.0.0.1';
    // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000
    // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口
    $gateway->startPort = 2900;
    // 服务注册地址
    $gateway->registerAddress = '127.0.0.1:1238';

    // 心跳间隔
    $gateway->pingInterval = 10;
    // 心跳数据
    $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();
    }

     5:修改start_register.php

    <?php

    use WorkermanWorker;
    use GatewayWorkerRegister;

    // 自动加载类
    require_once __DIR__ . '/../../vendor/autoload.php';

    // register 必须是text协议
    $register = new Register('text://0.0.0.0:1238');

    // 如果不是在根目录启动,则运行runAll方法
    if(!defined('GLOBAL_START'))
    {
    Worker::runAll();
    }

     6:将events放到index模块的controller下

    <?php
    namespace appindexcontroller

    /**

    * 声明:这里是处理业务逻辑的,跟聊天页面对应的东西,关联本页面是在push下的start_BusinessWorker这个文件里绑定引入到这里的
    * 用于检测业务代码死循环或者长时间阻塞等问题
    * 如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行php start.php reload
    * 然后观察一段时间workerman.log看是否有process_timeout异常
    */
    //declare(ticks=1);

    /**
    * 聊天主逻辑
    * 主要是处理 onMessage onClose
    */
    use GatewayWorkerLibGateway;

    class Events
    {
    /**
    * 有消息时
    * @param int $client_id
    * @param mixed $message
    */
    public static function onMessage($client_id, $message)
    {
    // debug
    echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']} client_id:$client_id session:".json_encode($_SESSION)." onMessage:".$message." ";
    // 客户端传递的是json数据
    $message_data = json_decode($message, true);
    if(!$message_data)
    {
    return ;
    }
    // 根据类型执行不同的业务
    switch($message_data['type'])
    {
    // 客户端回应服务端的心跳
    case 'pong':
    return;
    // 客户端登录 message格式: {type:login, name:xx, room_id:1} ,添加到客户端,广播给所有客户端xx进入聊天室
    case 'login':
    // 判断是否有房间号
    if(!isset($message_data['room_id']))
    {
    throw new Exception("$message_data['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']} $message:$message");
    }
    // 把房间号昵称放到session中
    $room_id = $message_data['room_id'];
    $client_name = htmlspecialchars($message_data['client_name']);
    $_SESSION['room_id'] = $room_id;
    $_SESSION['client_name'] = $client_name;

    // 获取房间内所有用户列表
    $clients_list = Gateway::getClientSessionsByGroup($room_id);
    foreach($clients_list as $tmp_client_id=>$item)
    {
    $clients_list[$tmp_client_id] = $item['client_name'];
    }
    $clients_list[$client_id] = $client_name;

    // 转播给当前房间的所有客户端,xx进入聊天室 message {type:login, client_id:xx, name:xx}
    $new_message = array('type'=>$message_data['type'], 'client_id'=>$client_id, 'client_name'=>htmlspecialchars($client_name), 'time'=>date('Y-m-d H:i:s'));
    Gateway::sendToGroup($room_id, json_encode($new_message));
    Gateway::joinGroup($client_id, $room_id);

    // 给当前用户发送用户列表
    $new_message['client_list'] = $clients_list;
    Gateway::sendToCurrentClient(json_encode($new_message));
    return;

    // 客户端发言 message: {type:say, to_client_id:xx, content:xx}
    case 'say':
    // 非法请求
    if(!isset($_SESSION['room_id']))
    {
    throw new Exception("$_SESSION['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
    }
    $room_id = $_SESSION['room_id'];
    $client_name = $_SESSION['client_name'];

    // 私聊
    if($message_data['to_client_id'] != 'all')
    {
    $new_message = array(
    'type'=>'say',
    'from_client_id'=>$client_id,
    'from_client_name' =>$client_name,
    'to_client_id'=>$message_data['to_client_id'],
    'content'=>"<b>对你说: </b>".nl2br(htmlspecialchars($message_data['content'])),
    'time'=>date('Y-m-d H:i:s'),
    );
    Gateway::sendToClient($message_data['to_client_id'], json_encode($new_message));
    $new_message['content'] = "<b>你对".htmlspecialchars($message_data['to_client_name'])."说: </b>".nl2br(htmlspecialchars($message_data['content']));
    return Gateway::sendToCurrentClient(json_encode($new_message));
    }

    $new_message = array(
    'type'=>'say',
    'from_client_id'=>$client_id,
    'from_client_name' =>$client_name,
    'to_client_id'=>'all',
    'content'=>nl2br(htmlspecialchars($message_data['content'])),
    'time'=>date('Y-m-d H:i:s'),
    );
    return Gateway::sendToGroup($room_id ,json_encode($new_message));
    }
    }

    /**
    * 当客户端断开连接时
    * @param integer $client_id 客户端id
    */
    public static function onClose($client_id)
    {
    // debug
    echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']} client_id:$client_id onClose:'' ";

    // 从房间的客户端列表中删除
    if(isset($_SESSION['room_id']))
    {
    $room_id = $_SESSION['room_id'];
    $new_message = array('type'=>'logout', 'from_client_id'=>$client_id, 'from_client_name'=>$_SESSION['client_name'], 'time'=>date('Y-m-d H:i:s'));
    Gateway::sendToGroup($room_id, json_encode($new_message));
    }
    }

    }

    7:index模块下新建viewindexindex.html

    <html><head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>workerman-chat PHP聊天室 Websocket(HTLM5/Flash)+PHP多进程socket实时推送技术</title>
    <script type="text/javascript">
    //WebSocket = null;
    </script>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/style.css" rel="stylesheet">
    <!-- Include these three JS files: -->
    <script type="text/javascript" src="/static/js/swfobject.js"></script>
    <script type="text/javascript" src="/static/js/web_socket.js"></script>
    <script type="text/javascript" src="/static/js/jquery.min.js"></script>

    <script type="text/javascript">
    if (typeof console == "undefined") { this.console = { log: function (msg) { } };}
    // 如果浏览器不支持websocket,会使用这个flash自动模拟websocket协议,此过程对开发者透明
    WEB_SOCKET_SWF_LOCATION = "/static/swf/WebSocketMain.swf";
    // 开启flash的websocket debug
    WEB_SOCKET_DEBUG = true;

    var ws, name, client_list={};

    // 连接服务端
    function connect() {
    // 创建websocket
    ws = new WebSocket("ws://"+document.domain+":8282");
    //console.log(ws);
    // 当socket连接打开时,输入用户名
    ws.onopen = onopen;
    // 当有消息时根据消息类型显示不同信息
    ws.onmessage = onmessage;
    ws.onclose = function() {
    console.log("连接关闭,定时重连");
    connect();
    };
    ws.onerror = function() {
    console.log("出现错误");
    };
    }

    // 连接建立时发送登录信息
    function onopen()
    {
    if(!name)
    {
    show_prompt();
    }
    // 登录
    var login_data = '{"type":"login","client_name":"'+name.replace(/"/g, '\"')+'","room_id":"<?php echo isset($_GET['room_id']) ? $_GET['room_id'] : 1?>"}';
    console.log("websocket握手成功,发送登录数据:"+login_data);
    ws.send(login_data);
    }

    // 服务端发来消息时
    function onmessage(e)
    {
    console.log(e.data);
    var data = eval("("+e.data+")");
    switch(data['type']){
    // 服务端ping客户端
    case 'ping':
    ws.send('{"type":"pong"}');
    break;;
    // 登录 更新用户列表
    case 'login':
    //{"type":"login","client_id":xxx,"client_name":"xxx","client_list":"[...]","time":"xxx"}
    say(data['client_id'], data['client_name'], data['client_name']+' 加入了聊天室', data['time']);
    if(data['client_list'])
    {
    client_list = data['client_list'];
    }
    else
    {
    client_list[data['client_id']] = data['client_name'];
    }
    flush_client_list();
    console.log(data['client_name']+"登录成功");
    break;
    // 发言
    case 'say':
    //{"type":"say","from_client_id":xxx,"to_client_id":"all/client_id","content":"xxx","time":"xxx"}
    say(data['from_client_id'], data['from_client_name'], data['content'], data['time']);
    break;
    // 用户退出 更新用户列表
    case 'logout':
    //{"type":"logout","client_id":xxx,"time":"xxx"}
    say(data['from_client_id'], data['from_client_name'], data['from_client_name']+' 退出了', data['time']);
    delete client_list[data['from_client_id']];
    flush_client_list();
    }
    }

    // 输入姓名
    function show_prompt(){
    name = prompt('输入你的名字:', '');
    if(!name || name=='null'){
    name = '游客';
    }
    }

    // 提交对话
    function onSubmit() {
    var input = document.getElementById("textarea");
    var to_client_id = $("#client_list option:selected").attr("value");
    var to_client_name = $("#client_list option:selected").text();
    ws.send('{"type":"say","to_client_id":"'+to_client_id+'","to_client_name":"'+to_client_name+'","content":"'+input.value.replace(/"/g, '\"').replace(/ /g,'\n').replace(/ /g, '\r')+'"}');
    input.value = "";
    input.focus();
    }

    // 刷新用户列表框
    function flush_client_list(){
    var userlist_window = $("#userlist");
    var client_list_slelect = $("#client_list");
    userlist_window.empty();
    client_list_slelect.empty();
    userlist_window.append('<h4>在线用户</h4><ul>');
    client_list_slelect.append('<option value="all" id="cli_all">所有人</option>');
    for(var p in client_list){
    userlist_window.append('<li id="'+p+'">'+client_list[p]+'</li>');
    client_list_slelect.append('<option value="'+p+'">'+client_list[p]+'</option>');
    }
    $("#client_list").val(select_client_id);
    userlist_window.append('</ul>');
    }

    // 发言
    function say(from_client_id, from_client_name, content, time){
    $("#dialog").append('<div class="speech_item"><img src="http://lorempixel.com/38/38/?'+from_client_id+'" class="user_icon" /> '+from_client_name+' <br> '+time+'<div style="clear:both;"></div><p class="triangle-isosceles top">'+content+'</p> </div>');
    }

    $(function(){
    select_client_id = 'all';
    $("#client_list").change(function(){
    select_client_id = $("#client_list option:selected").attr("value");
    });
    });
    </script>
    </head>
    <body onload="connect();">
    <div class="container">
    <div class="row clearfix">
    <div class="col-md-1 column">
    </div>
    <div class="col-md-6 column">
    <div class="thumbnail">
    <div class="caption" id="dialog"></div>
    </div>
    <form onsubmit="onSubmit(); return false;">
    <select style="margin-bottom:8px" id="client_list">
    <option value="all">所有人</option>
    </select>
    <textarea class="textarea thumbnail" id="textarea"></textarea>
    <div class="say-btn"><input type="submit" class="btn btn-default" value="发表" /></div>
    </form>
    <div>
    &nbsp;&nbsp;&nbsp;&nbsp;<b>房间列表:</b>(当前在&nbsp;房间<?php echo isset($_GET['room_id'])&&intval($_GET['room_id'])>0 ? intval($_GET['room_id']):1; ?>)<br>
    &nbsp;&nbsp;&nbsp;&nbsp;<a href="/?room_id=1">房间1</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="/?room_id=2">房间2</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="/?room_id=3">房间3</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="/?room_id=4">房间4</a>
    <br><br>
    </div>
    <p class="cp">PHP多进程+Websocket(HTML5/Flash)+PHP Socket实时推送技术&nbsp;&nbsp;&nbsp;&nbsp;Powered by <a href="http://www.workerman.net/workerman-chat" target="_blank">workerman-chat</a></p>
    </div>
    <div class="col-md-3 column">
    <div class="thumbnail">
    <div class="caption" id="userlist"></div>
    </div>
    <a href="http://workerman.net:8383" target="_blank"><img style="252px;margin-left:5px;" src="/img/workerman-todpole.png"></a>
    </div>
    </div>
    </div>
    </body>
    </html>

    8:start_for_win.bat

    php applicationpushstart_register.php applicationpushstart_gateway.php applicationpushstart_businessworker.php
    Pause

  • 相关阅读:
    [CF1076D] Edge Deletion
    [CF1081D] Maximum Distance
    [CF1095F] Make It Connected
    [CF1328E] Tree Queries
    [CF1328F] Make k Equal
    Codeforces Round #629 (Div. 3) 总结
    [CF1131D] Gourmet choice
    [CF1176D] Recover it!
    [CF1205B] Shortest Cycle
    [CF1213G] Path Queries
  • 原文地址:https://www.cnblogs.com/yszr/p/8547679.html
Copyright © 2011-2022 走看看