layim和Gatewayworker組合的實時通訊


今天是第二次重新開發使用layim和Gatewayworker,但是由於第一次沒有寫文檔,導致這一次就跟第一次一樣,一頭霧水,重新開始看文檔研究,導致遇到一個瓶頸,怎么都過不去。所以,以這篇文章開始,以后所有的知識點,全部寫上文檔。

首先如果是快速入手的快,直接從http://www.workerman.net/windows下載,worker。然后解壓放到項目中去。

,除了以上這三個文件,其他文件不需要做任何修改。

 

1 Events.php

這里面內容將是操控數據庫和實現頁面內容返回的地方,所以可以在這里面自定義任何方法。

<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * 用於檢測業務代碼死循環或者長時間阻塞等問題
 * 如果發現業務卡死,可以將下面declare打開(去掉//注釋),並執行php start.php reload
 * 然后觀察一段時間workerman.log看是否有process_timeout異常
 */
//declare(ticks=1);

// 自動加載類
use \GatewayWorker\Lib\Gateway;
use \GatewayWorker\Lib\DbConnection;
/**
 * 主邏輯
 * 主要是處理 onConnect onMessage onClose 三個方法
 * onConnect 和 onClose 如果不需要可以不用實現並刪除
 */
class Events
{
    public static $db;
    public static $uuid = [];
    public static $clientid = [];

    public static function onWorkerStart()
    {
        self::$db = new DbConnection('xxx', '3306', 'xxx', xxx', 'xxx');
    }

    /**
     * 當客戶端連接時觸發
     * 如果業務不需此回調可以刪除onConnect
     * 
     * @param int $client_id 連接id
     */
    public static function onConnect($client_id){
//        Gateway::sendToClient($client_id, json_encode($noonline));
    }
    
   /**
    * 當客戶端發來消息時觸發
    * @param int $client_id 連接id
    * @param mixed $message 具體消息
    */
   public static function onMessage($client_id, $message)
   {

       $data = json_decode($message,true);
        switch($data['type']) {
            //當有用戶上線
            case 'reg':
                //綁定uid 用於數據分發
                $uid = $data['data']['id'];
                Gateway::bindUid($client_id, $uid);
                self::$clientid[$client_id] = $uid;

                //如果數組中不存在鍵值uid,那么表示是第一次登陸,更新數據庫
                if(!isset(self::$uuid[$uid])){
                    self::$uuid[$uid] = $uid;
                    self::$db->update('im_user_baseInfo')->cols(array('status'=>1))->where('id='.$uid)->query();
                }
                break;

            case 'chatMessage':
                //正常聊天

                $to_user = $data['data']['to']['id'];
                $from_user = $data['data']['mine']['id'];
                $time = time();
                $content = quotationMarks($data['data']['mine']['content']);

                $msg = array(
                    'username'=>    $data['data']['mine']['username'],//消息來源用戶名
                    'avatar'=>     $data['data']['mine']['avatar'],
                    'id'=>         $from_user,//消息的來源ID(如果是私聊,則是用戶id,如果是群聊,則是群組id)
                    'content'=>    $content,
                    'type'=>       'friend',//聊天窗口來源類型,從發送消息傳遞的to里面獲取
                    'mine'=>       false,//是否我發送的消息,如果為true,則會顯示在右方
                    'timestamp'=>  date('Y-m-d h:i:s',$time),
                    'emit'=>       'chatMessage'
                );
                //發送給自己的,同客戶端同步
                $msg2 = array(
                    'username'=>    $data['data']['mine']['username'],//消息來源用戶名
                    'avatar'=>     $data['data']['mine']['avatar'],
                    'id'=>         $to_user,//消息的來源ID(如果是私聊,則是用戶id,如果是群聊,則是群組id)
                    'content'=>    $content,
                    'type'=>       'friend',//聊天窗口來源類型,從發送消息傳遞的to里面獲取
                    'mine'=>       true,//是否我發送的消息,如果為true,則會顯示在右方
                    'timestamp'=>  date('Y-m-d h:i:s',$time),
                    'emit'=>       'sendme'
                );
                $sql = array(
                    'from_user'=>$from_user,
                    'to_user'=>$to_user,
                    'type'=>1,//目前默認都是朋友
                    'content'=>$content,
                    'msg_type'=>1,//1:文本 2:資源(圖片,文件等)
                    'add_time'=>$time,
                    'is_read'=>1,//已經查看
                );

                //判斷是否在線
                if (Gateway::isUidOnline($to_user)) {
                    Gateway::sendToUid($to_user, json_encode($msg));
                    self::$db->insert('im_message')->cols($sql)->query();
                }
                else
                {
                    //如果對方離線,發送系統消息
                    $sql['is_read'] = 0;
                    self::$db->insert('im_message')->cols($sql)->query();

                    $noonline = array(
                        'emit'=>'status',
                        'fromid'=>-2,
                        'id'=>-2,
                        'status'=>0,
                    );
                    Gateway::sendToClient($client_id, json_encode($noonline));
                }

                //根據uid獲取其他客戶端的client_id
                $from_client_list = Gateway::getClientIdByUid($from_user);

                unset($from_client_list[array_search($client_id,$from_client_list)]);
                foreach ($from_client_list as $from_client){
                    Gateway::sendToClient($from_client, json_encode($msg2));
                }
                break;
            
            //查詢是否在線的狀態
            case 'status':
                $to_user = $data['data']['id'];
                $noonline = array(
                    'emit'=>'status',
                    'fromid'=>-2,
                    'id'=>-2,
                    'status'=>0
                );
                if (Gateway::isUidOnline($to_user)) {
                    $noonline['status'] = 1;
                }
                Gateway::sendToClient($client_id, json_encode($noonline));

                break;

            //修改聊天記錄為已讀狀態
            case 'isread':
                $username = quotationMarks($data['data']['name']);
                $uid = quotationMarks($data['data']['mid']);
                $from_user = self::getUserinfoByname($username);

                //改變消息的已讀狀態
                if(!empty($from_user) && !empty($uid)) self::changeIsread($from_user,$uid,1);
                break;
        }
        
   }
   
   /**
    * 當用戶斷開連接時觸發
    * @param int $client_id 連接id
    */
   public static function onClose($client_id)
   {
       $id = self::$clientid[$client_id];
       unset(self::$clientid[$client_id]);
       //如果長度等於0,說明綁定該uid的所有客戶端都下線了
       if(count(Gateway::getClientIdByUid($id)) == 0){
           unset(self::$uuid[$id]);
           self::$db->update('im_user_baseInfo')->cols(array('status'=>0))->where('id='.$id)->query();
       }
//       var_export(self::$clientid);

   }


    /**
     * 查詢該用戶名對應的用戶
     * @param $username
     * @return mixed
     */
    public static function getUserinfoByname($username){
        $result = self::$db->select('id')->from('im_user_baseInfo')->where("username= '$username' ")->column();
        return $result[0];
    }

    /**
     * Mobile將消息設置為已讀狀態
     * @param $from_user
     * @param $to_user
     * @param $is_read
     */
    public static function changeIsread($from_user,$to_user,$is_read){
        $sql = "UPDATE im_message SET is_read = $is_read WHERE from_user = $from_user AND to_user = $to_user";
        self::$db->query($sql);
    }



}
/**
 * 數據接收正則匹配,去掉字符串中的單引號和雙引號
 * add by fpc  time:2017-03-29
 */
function quotationMarks($str){
    // 正則表達式匹配中文(UTF8編碼)
    if(preg_match_all('/\'(.*?)\'/',$str)){
        $str = str_replace("\'",'',$str);
        if(preg_match_all('/\"(.*?)\"/',$str)){
            $str = str_replace('\"','',$str);
        }
        return trim($str);
    }else{
        return addslashes(trim($str));
    }
}
View Code

2start_businessworker.php

3start_gateway.php

4客戶端

總共就以上這些代碼,以上代碼僅在windows下的代碼,今天遇到一個問題,由於文件和方法是從linux移動過來的,所以調試的時候就出現了一下問題

服務器一直是可以的,但是使用

var socket = new WebSocket('ws://192.168.0.188:8484');打開的時候,就一直連接不上,原因就在於在start_gateway.phpz這個文件中,
$gateway = new Gateway("websocket://0.0.0.0:8484");這一句,linux是    tcp://..........  windows是websocket。
接下來就是無限發揮的時刻了

如果是https的服務器,那么使用
var socket = new WebSocket('wss://192.168.0.188:8484');




第二部分

摘要:在一個服務器上可以有多個 WebSocket部署

說明:第二個使用的是https

當我在同一個服務器上,使用workman部署第二個websocket的時候如圖所示為了防止端口號沖突,要修改端口號與以第一個部署的服務器的端口號全部不一樣

因為使用了https,與http的區別就是增加了這兩層代碼

在前台的js中

var socket = new WebSocket('wss://www.xxx.com:7272');  wss://域名+端口號,端口號要注意和gate的一致


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM