基于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();
  } 

}

完事!

原文地址:https://www.cnblogs.com/wadhf/p/11827834.html

时间: 2024-10-09 22:50:51

基于swoole实现多人聊天室的相关文章

【tcp-ip学习总结】基于udp的多人聊天室,带有登录注册功能

环境;vs2010,vs2013 服务器端 #include<stdio.h> #include<Winsock2.h> #include<stdlib.h> #pragma comment(lib,"Ws2_32.lib") typedef struct { char username[30];//用户名 char password[50];//用户密码 struct sockaddr_in addr;//用户的地址 int isOnlie;//是

android asmack 注册 登陆 聊天 多人聊天室 文件传输

XMPP协议简介 XMPP协议(Extensible Messaging and PresenceProtocol,可扩展消息处理现场协议)是一种基于XML的协议,目的是为了解决及时通信标准而提出来的,最早是在Jabber上实现的.它继承了在XML环境中灵活的发展性.因此,基于XMPP的应用具有超强的可扩展性.并且XML很易穿过防火墙,所以用XMPP构建的应用不易受到防火墙的阻碍.利用XMPP作为通用的传输机制,不同组织内的不同应用都可以进行有效的通信. 这篇文章有基本的介绍,http://bl

基于linux的TCP网络聊天室设计与实现

利用Linux实现基于TCP模式的网络聊天程序 主要完成的两大组成部分为:服务器和客户端. 服务器程序主要负责监听客户端发来的消息. 客户端需要登录到服务器端才可以实现正常的聊天功能.该程序是利用进程以及共享内存来实现群发送消息的. 以下简单分析一下服务器端和客户端两个方面所要完成的任务. 服务器的主要功能如下: 在特定的端口上进行监听,等待客户端的连接. 用户可以配置服务器端的监听端口. 向连接的客户端发送登录成功信息. 向已经连接到服务器的客户端的用户发送系统消息. 使用TCP多线程并发服务

使用node.js和socket.io实现多人聊天室

刚学node.js,想着做点东西练练手.网上的东西多而杂,走了不少弯路,花了一天时间在调代码上.参考网上的一篇文章,重写了部分代码,原来的是基于基于node-websocket-server框架的,我没用框架,单单是socket.io. 一.基本功能 1.用户随意输入一个昵称即可登录2.登录成功后1) 对正在登录用户来说,罗列所有在线用户列表,罗列最近的历史聊天记录2) 对已登录的用户来说,通知有新用户进入房间,更新在线用户列表3.退出登录1)支持直接退出2) 当有用户退出,其他所有在线用户会收

基于LBS的多人聊天

基于LBS的多人聊天,布布扣,bubuko.com

基于Select模型的混乱聊天室v1.0

最近在无聊完成了一个简单的基于select模型的匿名聊天室程序,均使用C++开发 服务器工作原理: 每接收一条客户端的信息,就将遍历所有的socket,并将该信息发给所有的客户端. 客户端使用两条线程,一个是接收服务端信息的线程,一个是等待阻塞输入的线程,获得输入时,将输入发送到服务器. 项目源码:https://github.com/coderguang/Chat 版本为v2.0的release. 其中ComLib也在github上 服务器核心代码: int main(int argc,cha

基于LINUX的多功能聊天室

原文:基于LINUX的多功能聊天室 基于LINUX的多功能聊天室 其实这个项目在我电脑已经躺了多时,最初写完项目规划后,我就认认真真地去实现了它,后来拿着这个项目区参加了面试,同样面试官也拿这个项目来问我,当然我是做过一遍了,而且为了面试,我将什么strcpy,strlen等最常用的函数都自己实现了一遍,说着,我感觉自己有点挺用功的样子呢! 后来,工作也定下来了,等三方,然后继续帮助我的导师做项目,经过老师的威逼利诱下,我屈服了,又把智能家居系统作为项目,同时也是我的毕业设计,而且功能还要十分完

基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室.

Spring整合DWR comet 实现无刷新 多人聊天室

用dwr的comet(推)来实现简单的无刷新多人聊天室,comet是长连接的一种.通常我们要实现无刷新,一般会使用到Ajax.Ajax 应用程序可以使用两种基本的方法解决这一问题:一种方法是浏览器每隔若干秒时间向服务器发出轮询以进行更新,另一种方法是服务器始终打开与浏览器的连接并在数据可用时发送给浏览器.第一种方法一般利用setTimeout或是setInterval定时请求,并返回最新数据,这无疑增加了服务器的负担,浪费了大量的资源.而第二种方法也会浪费服务器资源,长期的建立连接:而相对第一种