基于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编程语言开发动态WAP页面
Oct 09 PHP
Mysql和网页显示乱码解决方法集锦
Mar 27 PHP
PHP 远程关机实现代码
Nov 10 PHP
php数据库抽象层 PDO
May 07 PHP
使用 PHPMAILER 发送邮件实例应用
Nov 07 PHP
PHP 冒泡排序 二分查找 顺序查找 二维数组排序算法函数的详解
Jun 25 PHP
PHP远程采集图片详细教程
Jul 01 PHP
推荐一本PHP程序猿都应该拜读的书
Dec 31 PHP
php中mysql操作buffer用法详解
Mar 19 PHP
PHP通过文件路径获取文件名的实例代码
Oct 14 PHP
thinkphp3.2同时连接两个数据库的简单方法
Aug 13 PHP
如何在PHP环境中使用ProtoBuf数据格式
Jun 19 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
第八节 访问方式 [8]
2006/10/09 PHP
一个PHP并发访问实例代码
2012/09/06 PHP
phpize的深入理解
2013/06/03 PHP
PHP读取文件内容的五种方式
2015/12/28 PHP
laravel5.2实现区分前后台用户登录的方法
2017/01/11 PHP
PHP实现时间比较和时间差计算的方法示例
2017/07/24 PHP
thinkPHP5实现的查询数据库并返回json数据实例
2017/10/23 PHP
JS实现漂亮的时间选择框效果
2016/08/20 Javascript
wap手机端解决返回上一页的js实例
2016/12/08 Javascript
servlet+jquery实现文件上传进度条示例代码
2017/01/25 Javascript
JS实现页面打印功能
2017/03/16 Javascript
详解Vuex管理登录状态
2017/11/13 Javascript
微信小程序实现默认第一个选中变色效果
2018/07/17 Javascript
vue项目持久化存储数据的实现代码
2018/10/01 Javascript
帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
2019/08/23 Javascript
[26:21]浴火之凤-TI4世界冠军Newbee战队纪录片
2014/08/07 DOTA
[57:53]Secret vs Pain 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
python根据路径导入模块的方法
2014/09/30 Python
python中pandas.DataFrame排除特定行方法示例
2017/03/12 Python
利用Python实现Windows定时关机功能
2017/03/21 Python
pip安装Python库时遇到的问题及解决方法
2017/11/23 Python
Python实现快速计算词频功能示例
2018/06/25 Python
python实现加密的方式总结
2020/01/19 Python
python numpy实现rolling滚动案例
2020/06/08 Python
Python如何使用27行代码绘制星星图
2020/07/20 Python
Android本地应用打开方法——通过html5写连接
2016/03/11 HTML / CSS
英国厨房与餐具用品为主的设计品牌:Joseph Joseph
2018/04/26 全球购物
迪士尼法国在线商店:shopDisney FR
2020/12/03 全球购物
构造方法和其他方法的区别?怎么调用父类的构造方法
2013/09/22 面试题
学前班评语大全
2014/05/04 职场文书
森林防火标语
2014/06/23 职场文书
软件工程毕业生自荐信
2014/07/04 职场文书
大学生心理活动总结
2014/07/04 职场文书
解除租房协议书
2014/12/03 职场文书
小学数学教学反思范文
2016/02/16 职场文书
Redis基本数据类型哈希Hash常用操作命令
2022/06/01 Redis