当前位置:首页 > WebSocket > 正文内容

Workerman-写一个简单的websocket双向通信并实现MVC,用来开发游戏服务器

陈杰6个月前 (11-26)WebSocket456

最近在看Workerman,发现这是一个真的很好用的东西。


文档相当丰富,而且大神walker很贴心,有问必答。




下面记一下一个简单的基于GatewayWorker框架写的websocket的程序。


传统的websocket使用方式都是



1.客户端像服务器发送http请求,并发起websocket链接请求。


然后php框架调用GatewayWorker进行uid和websocket链接信息进行绑定。




2、客户端发送http请求交由php框架进行业务逻辑处理,返回给客户端HTTP Response。


再交由GatewayWorker把需要websocket通信的数据推送给其他用户。


例如Workerman推荐的就是使用此方式,可以很简单的集成一个类似客服系统,聊天系统。




看到这里我就想了一个问题,php能做什么?简单的curd?日复一日的在公司搬砖码代码,进行所谓的api开发?


Wokerman是一个基于PHP-CGI开发的多线程 无阻赛I/O的东西(我的理解哈)


那就可以用来做的事情就很多了




例如做一个简单的休闲游戏服务器???比如农场???


这种对实时通讯要求不太高的休闲小游戏就完全可以用PHP做服务器的开发嘛


再比如升级一点难度,做个完全实时双向通信的MMROPG游戏?




下面贴一下我简单的认识。


下载GatewayWorker


其他的代码都不需要改,注意改一下start_gateway.php里面的东西。


这里就先把"text://0.0.0.0:8282"


修改为websocket协议"websocket://0.0.0.0:8282"


然后PHP start.php 开启workerman服务


找个webscoket测试工具就能直接连接上了。。


<?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

 */

use \Workerman\Worker;

use \Workerman\WebServer;

use \GatewayWorker\Gateway;

use \GatewayWorker\BusinessWorker;

use \Workerman\Autoloader;


// 自动加载类

require_once __DIR__ . '/../../vendor/autoload.php';


// gateway 进程,这里使用Text协议,可以用telnet测试

$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();

}





修改Evnets.php


引入一个简单的路由类


use \Core\Router


并在onMessage回调函数中把所有的信息交给Router::run()来进行业务逻辑处理


Router::run();就是我们自定义的业务层的入口了


<?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;

use \Core\Router;


/**

 * 主逻辑

 * 主要是处理 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)

   {

       // 向所有人发送

       $data=Router::run($message);

       Gateway::sendToCurrentClient($data);

        //Gateway::sendToAll("$client_id said $message $data \r\n");

   }

   

   /**

    * 当用户断开连接时触发

    * @param int $client_id 连接id

    */

   public static function onClose($client_id)

   {

       // 向所有人发送 

       GateWay::sendToAll("$client_id logout\r\n");

   }

}


再来看看我们的Router类,其实就是一个简单的路由处理类。


通过比对客服端提交的json数据,再把请求数据交给具体的Controller来进行处理。


在路由规则中我们定义了test路由到Test控制器的test方法来进行业务处理。


而这时客服端提交的数据就应该是


{"route":"test"}就可以直接路由了。关于其他参数我们甚至可以


{"route":"test","user":{"uid":1,"token":2},"data":{"pk":true,"info":"list"}}


这里面可以传递token,等等等等。。。。。具体的交给我们的控制器操作进行了


甚至通过Controller 的Method返回来的数据我们可以再进行一次封装,比如数据参数不对啊,把客户端踢下线啊,我们经过自定义一个简单的type或者status然后switch一下,再来返回给客户端什么数据都是可以的。


<?php

/**

 * Created by PhpStorm.

 * User: 陈具龙

 * QQ:823380606

 * Date: 2019/7/20

 * Time: 23:05

 */


namespace Core;

/** Core核心路由类

 * Class Router

 * @package Core

 */

class Router{

    //配置规则路由

    public static $rules=array(

        'test'=>'Test@test'

    );

    public static function run($parm){

        $parm=json_decode($parm,true);

        if (key_exists($parm['route'],self::$rules)){

            $a=explode('@',self::$rules[$parm['route']]);

            $Controller='App\\Controller\\'.$a[0];

            $Method=$a[1];

            return $Controller::$Method();

            //    {"route":"test"}

        }else {

            //return json_encode($parm);

//            $arr=array(

//                'route'=>'test',

//                'user'=>array(

//                    'uid'=>1,

//                    'token'=>2,

//                ),

//                'data'=>array(

//                    'pk'=>true,

//                    'info'=>'list'

//                )

//            );

            return false;

        }

    }

}




现在MVC框架


C就是我们自定义的Controller


V就是GatewayWorker


就差M了。M引用一下thinkphp的orm


composer require topthink/think-orm


具体看https://github.com/top-think/think-orm


经过这一系列的操作,我们就相当于自己做了一个websocket的MVC框架了。




我们甚至可以把路由写得复杂一点,加入,消息加解密啊,中间件啊,命名空间啊,数据验证啊。我相信一个入门了两年以上的PHPer应该能很轻松自己把这些东西写出来吧。然后再统一一下Controller的返回数据,再交由Core进行统一调度,和前端同学统一一下格式,是不是就是像开发api接口一样简单?




而且用php做这方面的开发,性能比也不差,主要就是快啊,作为一个不想学习其他语言又拥有开发小游戏的同学来说真的是福音啊。下一步就是和node.js来做一个性能比较了,看看是不是真的可以这么用!!!!!


申研社-陈杰 http://blog.95shouyou.com/


扫描二维码至手机访问

扫描二维码推送至手机访问。

版权声明:本文由何烦过虎溪发布,如需转载请注明出处。

转载请注明出处:http://blog.95shouyou.com/?id=13

分享给朋友:

相关文章

workerman拆分events文件,实现常规编程习惯

workerman拆分events文件,实现常规编程习惯

wokerman的gateway很好用,自动解决了扩展性,分布式等较底层的东西。所有的逻辑代码只需要专注于events.php文件就行了,但是作者对于events编程的介绍比较少,如果从业多年的老手自...

nginx下反向代理开启websocket的wss服务

nginx下反向代理开启websocket的wss服务

通过nginx配置好网站的ssl证书后添加   location /wss  {    proxy_pass http://127.0.0.1:828...

uniapp的websocket无法监听到onSocketClose和onSocketError

项目框架使用的前端uniapp+后端laravel+workerman websocket写的,主要功能是聊天室系统。但是在开发完成实际体验过程中发现了一个有趣的现象。websocket老是无缘无故的...

laravel利用websocket搭建一个简单的实时聊天系统

laravel利用websocket搭建一个简单的实时聊天系统

主要实现功能就是用户之间的的实时聊天。理一下业务逻辑:用户A给用户B发送消息>如果用户B在线,直接通过websocket推送消息,用户B接受到消息后写入前端数据库,并归档数据>如果用户B不...

workerman中捕获notice错误并抛出异常

在workerman中出现了notice错误并不会中断程序运行,这是抛出一个无关紧要的提示,这显然与我们的程序设计初衷不符。例如我们去获取数组中的一个key-value值,当key不存在的时候只是提示...

申研社websocket通信规定

一、建立连接和维持连接 1、建立连接 测试地址ws://api.shenyanshe.95shouyou.com/websocket 2、约定客户端发送数据格式为 json字符串,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。