swoole_table使用方法

业务

业务背景

一款游戏双人匹配的app,匹配这个环节在我服务端(php) ,游戏的长连接在游戏端(node)

简单的来说:A和B玩游戏,A先进来,B此时也进入匹配,匹配成功.游戏开始

PHP异步框架的选择

  • workerman

    用过一段时间,因为他的共享数据的存储方式,只能依赖外部存储器,所以,我就直接pass了

  • swoole

    因为我只知道这两个,所以选了swoole.当然难度也会高很多..swoole这两年也是大红大紫啊

服务端长连接要做的事情(PHP)

  • 校验长连接匹配的参数,
  • 完成匹配环节
  • 获得游戏服务端(node),要的数据

这里主要说一下完成匹配过程中的共享数据的存储方式,A匹配进来,那么你必然要把A的一些数据存储起来,用户ID,匹配的游戏类型,只有这样,B匹配的时候,你才能去筛选啊,以前用的是Redis来作为外部存储器,但是后来接的..这种方式可能不是最佳的选择,于是就用了swoole_table

swoole_table表的设计

fd uid gameType data
文件描述符 用户主键ID 游戏类型 数据
INT INT STRING STRING

创建表

$table = new swoole_table(200000);
$table->column('fd', swoole_table::TYPE_INT);
$table->column('uid', swoole_table::TYPE_INT);
$table->column('gameType', swoole_table::TYPE_STRING, 256);
$table->column('data', swoole_table::TYPE_STRING, 256);
$table->create();
$this->server->table = $table;

整个流程实现思路

  • 匹配带token和gameType参数,自定义握手环节检测用户token和gameType,检测通过.数据存储到swoole_table中以 fd 为key
$this->server->on('handshake', function (\swoole_http_request $request, \swoole_http_response $response) use($handle) {
    // 校验参数
    if(参数不通过){
        $response->end();
        return false;
    }
    // 绑定这次游戏数据到$server,$gameInfo为你的游戏数据
    $this->server->gameInfo = $gameInfo;
    // 握手环节
    .......
    // 调用onopen
    $handle->onOpen($this->server,$request);
});
  • 正式握手成功之后,在onopen做匹配,读取swoole_table数据,如果有人在匹配就直接取出用户,同时读取用户数据,返回,,如果没人,把数据写入swool_table
//准备要存储的数据
$data = [
            'fd'       => $fd,
            'uid'      => $user['id'],
            'gameType' => $gameType,
            'data'     => json_encode($user)
        ];
//检索数据是否有人在匹配中..
$rival = [];
foreach ($server->table as $key => $item) {
    if ($item['gameType'] == $gameType) {
        $rival = $item;
        continue;
    }
}
if ($rival) {
 //获取数据,给双方发送数据,断开连接
}else{
 //存入数据,自己作为第一个匹配者
 $server->table->set($fd, $data);
}
  • 处理断开事件

    不管你是匹配到玩家断开的连接,还是自己断开的,都应该删除表中的脏数据

 public function onClose ($server, $fd)
{
    if ($server->table->exist($fd)) {
        $server->table->del($fd);
    }
}