基于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 相关文章推荐
memcached 和 mysql 主从环境下php开发代码详解
May 16 PHP
jQuery+PHP实现的掷色子抽奖游戏实例
Jan 04 PHP
十幅图告诉你什么是PHP引用
Feb 22 PHP
PHP截取IE浏览器并缩小原图的方法
Mar 04 PHP
PHP 500报错的快速解决方法
Dec 14 PHP
微信公众号OAuth2.0网页授权问题浅析
Jan 21 PHP
浅析PHP数据导出知识点
Feb 17 PHP
php实现websocket实时消息推送
Mar 30 PHP
ThinkPHP 3.2.3实现加减乘除图片验证码
Dec 05 PHP
PHP各种常见经典算法总结【排序、查找、翻转等】
Aug 05 PHP
零基础php编程好学吗
Oct 11 PHP
Laravel5.1 框架表单验证操作实例详解
Jan 07 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
url decode problem 解决方法
2011/12/26 PHP
PHP捕获Fatal error错误的方法
2014/06/11 PHP
SSO单点登录的PHP实现方法(Laravel框架)
2016/03/23 PHP
PHP校验15位和18位身份证号的类封装
2018/11/07 PHP
YUI 读码日记之 YAHOO.util.Dom - Part.1
2008/03/22 Javascript
JQuery select标签操作代码段
2010/05/16 Javascript
jquery弹出关闭遮罩层实例
2013/08/06 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
2016/06/06 Javascript
jQuery Easyui学习教程之实现datagrid在没有数据时显示相关提示内容
2016/07/09 Javascript
浅谈webpack组织模块的原理
2018/03/10 Javascript
webstorm中vue语法的支持详解
2018/05/09 Javascript
Async/Await替代Promise的6个理由
2019/06/15 Javascript
详解python3中用HTMLTestRunner.py报ImportError: No module named 'StringIO'如何解决
2019/08/27 Python
python如何使用jt400.jar包代码实例
2019/12/20 Python
pytorch中获取模型input/output shape实例
2019/12/30 Python
使用Django xadmin 实现修改时间选择器为不可输入状态
2020/03/30 Python
无需压缩软件,用python帮你操作压缩包
2020/08/17 Python
纯CSS3实现鼠标滑过按钮动画第二节
2020/07/16 HTML / CSS
HTML5页面音视频在微信和app下自动播放的实现方法
2016/10/20 HTML / CSS
Theflamel意大利:女士奢华服装、鞋子和配件
2020/01/11 全球购物
Ruby如何创建一个线程
2013/03/10 面试题
20岁生日感言
2014/01/13 职场文书
高二生物教学反思
2014/01/27 职场文书
宗教学大学生职业生涯规划范文
2014/02/08 职场文书
北京奥运会主题口号
2014/06/13 职场文书
社区精神文明建设汇报材料
2014/08/17 职场文书
三方股份合作协议书
2014/10/13 职场文书
儿园租房协议书范本
2014/12/02 职场文书
团组织推优材料
2014/12/29 职场文书
教师节感谢信
2015/01/22 职场文书
结婚堵门保证书
2015/05/08 职场文书
用电申请报告范文
2015/05/18 职场文书
党支部评议意见
2015/06/02 职场文书
无婚姻登记记录证明
2015/06/18 职场文书
windows11怎么查看wifi密码? win11查看wifi密码的技巧
2021/11/21 数码科技
详解Spring Security如何在权限中使用通配符
2022/06/28 Java/Android