swoole實現多對多羣聊(一)

參考博客,大家可以去看看原文,這裏只是根據業務需求做了更改
後端參考
swoole創建多人多房間聊天室一
swoole創建多人多房間聊天室二
swoole創建多人多房間聊天室三
前端參考
微信小程序開發聊天室

搭建環境和域名配置這裏就先跳過了,大家可以自行百度
話不多說直接上代碼

PHP代碼

<?php

define('HOST', '0.0.0.0');
define('PORT', '19501');
define('WORKER_NUM', 10);
define('DISPATCH_MODE', 2);
define('DAEMONIZE', 0);

class WebsocktDemo
{
    public $ws = null;
    public $redis = null;
    public function __construct()
    {

        $this->ws = new Swoole\WebSocket\Server(HOST, PORT);
        $this->redis = $this->redis();
        $this->redis->auth("***********");

        //$this->ws->on("start", [$this, 'onStart']);
        $this->ws->on("open", [$this, 'onOpen']);
        $this->ws->on('message',[$this,'onMessage']);
        $this->ws->on('close',[$this,'onClose']);
        $this->ws->start();
    }
	/**
     * 獲取redis實例
     * @return null|Redis
     */
    protected function redis()
    {
        static $redis = null;
        if (is_null($redis)) {
            $redis = new \Redis();
            $redis->connect("*********");
        }

        return $redis;
    }
    
    /**
     * 監聽用戶鏈接事件,鏈接時需要帶用戶id與房間id參數,再把用戶存到房間域中
     */
    public function onOpen($server, $request){
        //加入房間域
        $this->redis->hset($request->get['room'], $request->get['uid'], $request->fd);
        //加入組集合
        $this->redis->sadd('group', $request->get['room']);
    }
    
    /**
     * 監聽接收事件的回調
     */
    public function onMessage($server, $frame)
    {
        //在接收數據的時候進行推送,每次發送消息都要帶上標記信息(uid,room)
        $data = json_decode($frame->data, true);
        //組裝數據判斷類型
        switch ($data['type']){
            case "change"://發送消息
                $arr['name'] = $data['name'];
                $arr['content'] = $data['content'];
                $arr['type'] = "change";
                $arr['uid'] = $data['uid'];
                $arr['room'] = $data['room'];
                break;
        }
        //推送消息到房間,
        self::push_room($data['room'], $arr);
    }
    
	/**
     * 監聽關閉事件的回調,這一步照搬,沒有做修改
     */
    public function onClose($ser, $fd)
    {
        //退出並刪除多餘的分組fd
        $group = $this->redis->sMembers('group');
        foreach ($group as $v) {
            $fangjian = $this->redis->hgetall($v);
            foreach ($fangjian as $k => $vv) {
                if ($fd == $vv) {
                    $this->redis->hdel($v, $k);
                }
            }
        }
    }
  }
  //最後實例化對象
  new WebsocktDemo();
    

後端的代碼主要是用到Swoole的WebSocket 服務和redis hash域的概念,剛開始做的時候並沒有想到使用redis,而是直接去鏈接數據實現的,後來參考了別人的文章,豁然開朗,換成了redis(手動滑稽),順便了解了一下redis的hsah

小程序 websocket.js 代碼

// 請求域名
var url = 'wss://你的wss域名';
// 房間信息
var room = ''
// 用戶簽名
var sign = 0
// 用戶名
var name = null;
// 收到消息回調函數
var func = null;

function connect(room,sign,name,func) {
  //把鏈接信息全局化的目的爲斷開後實現重新鏈接,*如果前端通過超過一分鐘沒有與socket交互就會自動斷開
  let that = this
  room = room
  sign = sign
  name = name
  func = func
  wx.connectSocket({
    url: url + "?room="+room+"&uid="+sign+"&name="+name,
    method: 'post',
    header:{'content-type': 'application/json'},
    success: function (res) {
      console.log('連接成功',res)
    },
    fail: function (res) {
      console.log('連接失敗',res)
      wx.closeSocket()
    }
  })
  wx.onSocketOpen(function (res) {
     //接受服務器消息
     wx.onSocketMessage(func);//func回調可以拿到服務器返回的數據
  });
  wx.onSocketClose(function (res) {
    console.log("鏈接失敗",res);
    if(res.reason == "abnormal closure" && res.code == 1006){//實現重連
      that.connect(room,sign,name,func);
    }
  });
}
//發送消息
function send(msg,callbackll) {
  wx.sendSocketMessage({
    data: msg,
    complete(res){
      callbackll(res);
    }
  });
}
module.exports = {
  connect: connect,
  send: send
}

小程序 js 代碼

import websocket from "../utils/websocket.js";
//頁面加載就鏈接soket,監聽服務器返回消息
onLoad: function (options) {
	websocket.connect(options.id, wx.getStorageSync("sign"), nickname, function (res) {
		//監聽接受到數據回調時間
		let server = JSON.parse(res.data)
		that.setData({
			bullet_screen: that.data.bullet_screen.concat(server)
		})
	})
}
// 發送到socket
send: function (e) {
  let that = this
  if (that.data.msgContent == '') {
    wx.showToast({
      title: '請輸入您想說的話',
      icon: 'none',
      duration: 2000
    })
    return false
  }
  websocket.send('{"name":"' + wx.getStorageSync("nickname") + '","uid":"' + wx.getStorageSync("sign") + '","type":"change","room": "' + that.data.roomid + '","content": "' + that.data.msgContent + '"}', function (call) {
    if (call.errMsg == "sendSocketMessage:fail WebSocket is not connected") {
      wx.showToast({
        title: '發送失敗',
        icon: "none",
        duration: 2000
      })
      return false;
    }
    that.setData({
      msgContent: ''
    })
  })
}

前端主要是使用微信小程序的websocket鏈接API,可以把整個websocket封裝成一個工具類。
js的話只有兩段核心代碼,一個是前端鏈接socket後拿到返回消息的處理,其次就是發送消息到socket,整體前後端代碼核心部分就只有這麼多了,跟其他博客大同小異,主要是看大家的業務需求和實現方式的不同。
前端html這裏就不一一展示了,主要就是循環服務器返回的數組,再根據不同的type值添加css樣式,就可以實現一些特殊的樣式需求了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章