- thinkPHP3.2 與workerman 結合
- 首先下載wokerman,放到TP項目下面的ThinkPHP/Library目錄,並命名爲Workerman
- 除Constants.php以外的所有php文件改爲.class.php後綴
- 代碼塊
Js代碼
var uid = sessionStorage.getItem('userid'); // 登錄平臺用戶id, 登錄時存入 var ws = new WebSocket("ws://127.0.0.1:2346"); // 連接socket // 初始化連接 ws.onopen = function() { console.log("連接成功"); if(uid != null){ ws.send(userid); // 發送數據到後端 } }; // 返回信息 ws.onmessage = function(evt){ var res = evt.data; if(JSON.parse(res).code == 1001){ layer.msg(JSON.parse(res).msg,{icon:6,time:2000},function(){ sessionStorage.removeItem('userid'); // 清楚瀏覽器userid window.location.href = 'url'; // 退出接口 }); } }
登錄成功後
ws.send(“用戶id”);
PHP代碼塊: 新建一個WorkerController.class.php 控制器
<?php namespace Cli\Controller; use Think\Controller; use Workerman\Worker; use Workerman\Lib\Timer; use Redis; // 心跳間隔時間 define('HEARTBEAT_TIME', 3600); class WorkermanController { protected $redis = ''; protected $data = ''; protected $msg = ['code' => 0, 'msg' => '您的賬號已在別處登錄']; /** * 構造函數 * @access public */ public function __construct() { // 實例化 Websocket 服務 $this->worker = new \Workerman\Worker('websocket://0.0.0.0:2346'); $this->worker->count = 4;// 設置進程數 $this->init();//初始化 // 設置回調 foreach (['onWorkerStart', 'onConnect', 'onMessage', 'onClose', 'onError', 'onBufferFull', 'onBufferDrain', 'onWorkerStop', 'onWorkerReload'] as $event) { if (method_exists($this, $event)) { $this->worker->$event = [$this, $event]; } } // Run worker Worker::runAll(); } /** * 收到信息 * @param $connection * @param $data */ public function onMessage($connection, $data) { $this->data = $data; //登錄連接時分配一個全局唯一的uid $connection->uid = uniqid('xxx_'); //追入redis中 $this->redis->hSet('key',$connection->uid, $data); $expireTime = mktime(23, 59, 59, date("m"), date("d"), date("Y")); //設置鍵的過期時間 $this ->redis->expireAt('hxt', $expireTime); } /** * 當連接建立時觸發的回調函數 * @param $connection */ public function onConnect($connection) { // redis 不存在則實例化Redis對象, 並連接 if($this->redis == ''){ $this->redis = new Redis(); $this->redis->connect('127.0.0.1',6379); } } /** * 當連接斷開時觸發的回調函數 * @param $connection */ public function onClose($connection) { if(isset($connection ->uid)){ //找出userid 對應key $cid = $connection ->uid; //清除redis中對應id $this ->redis ->hDel('key',$cid); } } /** * 當客戶端的連接上發生錯誤時觸發 * @param $connection * @param $code * @param $msg */ public function onError($connection, $code, $msg) { echo "error $code $msg\n"; } /** * 每個進程啓動 * @param $worker */ public function onWorkerStart($worker) { //var_dump($worker->connections); Timer::add(1, function()use($worker){ $time_now = time(); if($this->redis == ''){ $this->redis = new Redis(); $this->redis->connect('127.0.0.1',6379); } //取出redis中所有連接客戶端key $arr = $this->redis->hGetAll('key'); //查詢當前登錄id是否在redis中 $true = array_search($this->data,$arr); $sum=$this->get_array_repeats($tarr,$this->data); foreach($worker->connections as $connection) { if(isset($connection ->uid) && $connection->uid == $true && $sum>=2){ $connection->send(json_encode($this->msg)); // 發送給客戶端 $connection->close(); } $jicheng = $connection; // 有可能該connection還沒收到過消息,則lastMessageTime設置爲當前時間 if (empty($jicheng->lastMessageTime)) { $jicheng->lastMessageTime = $time_now; continue; } // 上次通訊時間間隔大於心跳間隔,則認爲客戶端已經下線,關閉連接 if ($time_now - $jicheng->lastMessageTime > HEARTBEAT_TIME) { // $connection->close(); echo "下線"; } } }); } //計算$string在$array(需爲數組)中重複出現的次數 public function get_array_repeats(array $array,$string) { $count = array_count_values($array); //統計中重複元素的次數,再重組數組, if (key_exists($string,$count)) { return $count[$string]; }else{ return 0; } } public function init(){ } }
- 開啓Redis服務
- 開啓worker 服務
到這裏就實現了 thinkPHP3.2 + Redis + workerman 就完成了賬號單點登錄
2. thinkPHP5 與 Redis + workerman 實現
workerman 的安裝:thinkPHP5可以直接用composer 安裝workerman 擴展,具體方法請自行參考thinkPHP5官方文檔
js與上面的相同,自行參考
PHP代碼部分:
一、在項目跟目錄新建一個server.php 文件 ,代碼如下:
<?php define('APP_PATH', __DIR__ . '/application/'); define('BIND_MODULE','push/Worker'); // 加載框架引導文件 require __DIR__ . '/thinkphp/start.php';
二、建立push模塊並建立worker.php 文件, 代碼如下:
<?php namespace app\push\controller; use think\worker\Server; use workerman\Workerman; use Redis; class Worker extends Server { // 代碼塊跟tp3.2 worker文件代碼相同,不做處理 }
最後同上:開啓Redis , 在跟目錄開啓server服務
php server.php