基于swoole实现多人聊天室


Posted in PHP onJune 14, 2018

本文实例为大家分享了swoole创建多人多房间聊天室的具体代码,供大家参考,具体内容如下

核心的swoole代码

基本的cs(client-sercer)结构不变,这里利用的是redis的哈希和set来储存和分组;从而达到了分组,统计,定时推送等功能;最后利用onclose事件来剔除断开的连接,全部代码如下:(没做前端,就不展示了)

核心的swoole ws.php

<?php 
 
namespace app\common; 
require_once 'Predis.php'; 
require_once 'Task.php'; 
/** 
*  socket面向对象的编译 
*/ 
class Ws 
{ 
  CONST HOST='0.0.0.0'; 
  CONST PORT='9501'; 
  public $ws=null; 
  public $getmsg=null; 
  public $server=null; 
 
  public function __construct() 
  {   
    $this->ws=new \swoole_websocket_server(self::HOST,self::PORT); 
    $this->ws->set([ 
      //启动task必须要设置其数量 
      'worker_num' => 4, 
      'task_worker_num' => 2, 
      // 'heartbeat_check_interval' => 5, 
      // 'heartbeat_idle_time' => 10, 
    ]); 
    //监听新端口 
    $this->server=$this->ws->listen("127.0.0.1", 9502, SWOOLE_SOCK_TCP); 
    //关闭websocket模式 
    $this->server->set([ 
      'open_websocket_protocol' => false, 
    ]); 
 
    $this->ws->on("start", [$this, 'onStart']); 
    $this->ws->on('open',[$this,'onopen']); 
    $this->server->on("receive", [$this, 'onReceive']); 
    $this->ws->on('task',[$this,'onTask']); 
    $this->ws->on('finish',[$this,'onFinish']); 
    $this->ws->on('message',[$this,'onmessage']); 
    $this->ws->on('close',[$this,'onclose']); 
    $this->server->on("close", [$this, 'oncloses']); 
    $this->ws->start(); 
  } 
  //监听数据接收事件 
  public function onReceive($serv, $fd, $from_id, $data) 
  { 
    $shuju=json_decode($data,ture); 
    // print_r($shuju).PHP_EOL; 
    if (empty($shuju['data'])) { 
      $this->ws->push(Predis::getInstance()->get('fd'), $data); 
    }else{ 
      if (empty($shuju['msg'])) { 
        //执行异步任务 
        $this->ws->task($shuju); 
      }else{ 
        $push_arr=Predis::getInstance()->hvals($shuju['data']); 
        // echo "集群是:".print_r($push_arr); 
        foreach ($push_arr as $v) { 
          $this->ws->push($v, $shuju['msg']); 
        } 
      } 
    } 
  } 
  /** 
   * 设置进程名,为后续平滑重启进程 
   * @param $server 
   */ 
  public function onStart($server) { 
    swoole_set_process_name("live_master"); 
  }    
  /** 
    监听开启事件的回调 
  */ 
  public function onopen($server, $request) 
  { 
    print_r("这时的fd是:",$request->fd); 
    Predis::getInstance()->set('fd',$request->fd); 
  } 
   
  /** 
    监听接收事件的回调 
  */ 
  public function onmessage($server, $frame) 
  { 
    $server->push($frame->fd, "{$frame->data}"); 
  } 
  /** 
    监听关闭事件的回调 
  */ 
  public function onclose($ser, $fd) 
  { 
    print_r("你好,我的{$fd}\n"); 
    //退出并删除多余的分组fd 
    $group=Predis::getInstance()->sMembers('group'); 
    foreach ($group as $v) { 
      $fangjian=Predis::getInstance()->hgetall($v); 
      foreach ($fangjian as $k => $vv) { 
        if ($fd == $vv) { 
          Predis::getInstance()->hdel($v,$k); 
        } 
      } 
    } 
  } 
  public function oncloses($ser, $fd) 
  { 
    print_r("这个是client{$fd}\n"); 
  } 
 
  /** 
  *  $serv      服务 
  *  $task_id    任务ID,由swoole扩展内自动生成,用于区分不同的任务 
  *  $src_worker_id $task_id和$src_worker_id组合起来才是全局唯一的,不同的worker进程投递的任务ID可能会有相同 
  *  $data      是任务的内容 
  */ 
   public function onTask($serv,$task_id,$src_worker_id,$data) 
  { 
    //引入任务 
    $obj = new Task; 
    $method = $data['data']; 
    $arr = $data['arr']; 
    //发布具体的任务 
    $flag = $obj->$method($arr, $serv); 
    return $flag; // 告诉worker 
  } 
  /** 
  *  $task_id    是任务的ID 
  *  $data      是任务处理的结果内容 
  */ 
   public function onFinish($serv,$task_id,$data) 
  { 
    print_r($data).'/n'; 
  } 
 
} 
 
new Ws();

分发任务task.php

<?php 
/** 
 * 代表的是 swoole里面 后续 所有 task异步 任务 都放这里来 
 * Date: 18/3/27 
 * Time: 上午1:20 
 */ 
namespace app\common; 
// include 'Predis.php'; 
 
class Task { 
  //异步创建房间 
  public function chuangjian($data,$serv) 
  { 
    $time=$data['time']*1000; 
    swoole_timer_after($time, function() use($data){ 
      //创建房间(修改拍卖商品状态) 
      self::post("https://code.77wx.cn/index/index/in"); 
    }); 
  } 
 
  //进入房间并缓存信息 
  public function jingru($data,$serv) 
  { 
    $fd=Predis::getInstance()->get('fd'); 
    //加入分组 
    Predis::getInstance()->hset($data['name'],$data['uid'],$fd); 
    //加入组集合 
    Predis::getInstance()->sadd('group',$data['name']); 
  } 
 
 
  public function post($url,$params=false,$ispost=0) 
  { 
    $httpInfo = array(); 
    $ch = curl_init(); 
    curl_setopt( $ch, CURLOPT_HTTP_VERSION , CURL_HTTP_VERSION_1_1 ); 
    curl_setopt( $ch, CURLOPT_USERAGENT , 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22' ); 
    curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT , 30 ); 
    curl_setopt( $ch, CURLOPT_TIMEOUT , 30); 
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER , true ); 
    if( $ispost ) 
    { 
      curl_setopt( $ch , CURLOPT_POST , true ); 
      curl_setopt( $ch , CURLOPT_POSTFIELDS , $params ); 
      curl_setopt( $ch , CURLOPT_URL , $url ); 
    } 
    else 
    { 
      if($params){ 
        curl_setopt( $ch , CURLOPT_URL , $url.'?'.$params ); 
      }else{ 
        curl_setopt( $ch , CURLOPT_URL , $url); 
      } 
    } 
    //执行 
    $response = curl_exec( $ch ); 
    if ($response === FALSE) { 
      //echo "cURL Error: " . curl_error($ch); 
      return false; 
    } 
 
    $httpCode = curl_getinfo( $ch , CURLINFO_HTTP_CODE ); 
    $httpInfo = array_merge( $httpInfo , curl_getinfo( $ch ) ); 
    //关闭url请求 
    curl_close( $ch ); 
    return json_decode($response,1); 
  } 
 
}

客户端 client.php

<?php 
namespace app\common; 
 
class Client 
{ 
  public $msg=''; 
 
  public $data=[]; 
 
  public function lianjie(){ 
 
    $cli = new \swoole_client(SWOOLE_SOCK_TCP); 
    //判断连接状态(同步连接模式) 
    $res=$cli->connect('127.0.0.1', 9502); 
    if (empty($res)) { 
      return "连接失败"; 
    } 
 
    if (!empty($this->data)) { 
      //发送消息给server 
      $rel=$cli->send(json_encode($this->data)); 
    }else{ 
      //发送消息给server 
      $rel=$cli->send($this->msg); 
    } 
    if (!empty($rel)) { 
      return $rel; 
    }else{ 
      return flash; 
    } 
  } 
}

 控制器index.php

<?php 
namespace app\index\controller; 
 
use app\common\Client; 
use app\common\Predis; 
use app\common\Sql; 
use app\index\model\User; 
 
class Index 
{ 
  //创建房间(添加拍卖倒计时) 
  public function chuangjian() 
  { 
    $data['time']=input("time"); 
    $data['id']=input("id"); 
    $cli = new Client(); 
    $cli->data = [ 
      'data' => 'chuangjian', 
      'arr' => $data 
    ]; 
    return $cli->lianjie(); 
  } 
  //点击添加哈希(进入房间) 
  public function jingru() 
  { 
    $data['name']=input("name"); 
    $data['uid']=input("uid"); 
    $cli = new Client(); 
    $cli->data = [ 
      'data' => 'jingru', 
      'arr' => $data 
    ]; 
    return $cli->lianjie(); 
  } 
  //本房间推送(出价格成功并推送) 
  public function pushfan() 
  { 
    $data['fan']=input("fan"); 
    $cli = new Client(); 
    $cli->data = [ 
      'data' => $data['fan'], 
      'msg' => "恭喜用户111,喜当爹!!!!" 
    ]; 
    return $cli->lianjie(); 
  } 
  //时间结束并指定推送 
  public function zhiding() 
  { 
    $data['fan']=input("fan"); 
    $cli = new Client(); 
    $cli->data = [ 
      'data' => $data['fan'], 
      'msg' => "恭喜用户111,喜当爹!!!!" 
    ]; 
    return $cli->lianjie(); 
  } 
 
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php 进度条实现代码
Mar 10 PHP
php中对2个数组相加的函数
Jun 24 PHP
PHP创建桌面快捷方式的实例代码
Feb 17 PHP
PHP实现的博客欢迎提示功能(很特别哦)
Jun 05 PHP
php微信公众平台开发(一) 配置接口
Dec 06 PHP
PHP使用Redis替代文件存储Session的方法
Feb 15 PHP
PHP编程实现多维数组按照某个键值排序的方法小结【2种方法】
Apr 27 PHP
iis6手工创建网站后无法运行php脚本的解决方法
Jun 08 PHP
thinkphp 抓取网站的内容并且保存到本地的实例详解
Aug 25 PHP
在php的yii2框架中整合hbase库的方法
Sep 20 PHP
php实现 master-worker 守护多进程模式的实例代码
Jul 20 PHP
laravel Model 执行事务的实现
Oct 10 PHP
PHP实现数组转JSon和JSon转数组的方法示例
Jun 14 #PHP
php实现微信公众平台发红包功能
Jun 14 #PHP
ThinkPHP3.2框架自定义配置和加载用法示例
Jun 14 #PHP
thinkPHP框架实现多表查询的方法
Jun 14 #PHP
php微信开发之关注事件
Jun 14 #PHP
thinkPHP框架动态配置用法实例分析
Jun 14 #PHP
php微信开发之谷歌测距
Jun 14 #PHP
You might like
php调用MySQL存储过程的方法集合(推荐)
2013/07/03 PHP
Apache服务器下防止图片盗链的办法
2015/07/06 PHP
PHP实现合并discuz用户
2015/08/05 PHP
WordPress中给文章添加自定义字段及后台编辑功能区域
2015/12/19 PHP
PHP实现的redis主从数据库状态检测功能示例
2017/07/20 PHP
PHP检测接口Traversable用法详解
2017/12/29 PHP
php生成短网址/短链接原理和用法实例分析
2020/05/29 PHP
JQuery.ajax传递中文参数的解决方法 推荐
2011/03/28 Javascript
js 实现 input type=&quot;file&quot; 文件上传示例代码
2013/08/07 Javascript
解析JavaScript中的不可见数据类型
2013/12/02 Javascript
jQuery实现防止提交按钮被双击的方法
2015/03/24 Javascript
javascript实现随时变化着的背景颜色
2015/04/02 Javascript
JS拖动鼠标画出方框实现鼠标选区的方法
2015/08/05 Javascript
vue数据双向绑定原理解析(get &amp; set)
2017/03/08 Javascript
为Jquery EasyUI 组件加上清除功能的方法(详解)
2017/04/13 jQuery
原生js中ajax访问的实例详解
2017/09/19 Javascript
nodejs中安装ghost出错的原因及解决方法
2017/10/23 NodeJs
代码详解javascript模块加载器
2018/03/04 Javascript
详解vue-cli 2.0配置文件(小结)
2019/01/14 Javascript
JQuery animate动画应用示例
2019/05/14 jQuery
layer.open提交子页面的form和layedit文本编辑内容的方法
2019/09/27 Javascript
原生js实现的金山打字小游戏(实例代码详解)
2020/03/16 Javascript
在Python中使用Neo4j数据库的教程
2015/04/16 Python
利用Python学习RabbitMQ消息队列
2015/11/30 Python
Python进阶学习之特殊方法实例详析
2017/12/01 Python
python修改list中所有元素类型的三种方法
2018/04/09 Python
python logging添加filter教程
2019/12/24 Python
CSS3与动画有关的属性transition、animation、transform对比(史上最全版)
2017/08/18 HTML / CSS
会计出纳员的自我评价
2014/01/15 职场文书
简历中的自我评价范文
2014/02/05 职场文书
五星级酒店餐饮部总监的标准岗位职责
2014/02/17 职场文书
运动员获奖感言
2014/08/15 职场文书
城市规划应届生推荐信
2014/09/08 职场文书
安全主题班会教案
2015/08/12 职场文书
Oracle设置DB、监听和EM开机启动的方法
2021/04/25 Oracle
python+pytest接口自动化之token关联登录的实现
2022/04/06 Python