今天是第二次重新開發使用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)); } }
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的一致