相關關鍵詞
關于我們
最新文章
php中Redis的應用--消息傳遞

閱讀目錄
1、摘要
2、實現(xiàn)方法
3、一對一消息傳遞
4、多對多消息傳遞
1、摘要
消息傳遞這一應用廣泛存在于各個網站中,這個功能也是一個網站必不可少的。常見的消息傳遞應用有,新浪微博中的@我呀、給你評論然后的提示呀、贊贊贊提示、私信呀、甚至是發(fā)微博分享的新鮮事;知乎中的私信呀、live發(fā)送過來的消息、知乎團隊消息呀等等。
2、實現(xiàn)方法
消息傳遞即兩個或者多個客戶端在相互發(fā)送和接收消息。
通常有兩種方法實現(xiàn):
第一種為消息推送。Redis內置有這種機制,publish往頻道推送消息、subscribe訂閱頻道。這種方法有一個缺點就是必須保證接收者時刻在線(即是此時程序不能停下來,一直保持監(jiān)控狀態(tài),假若斷線后就會出現(xiàn)客戶端丟失信息)
第二種為消息拉取。所謂消息拉取,就是客戶端自主去獲取存儲在服務器中的數(shù)據(jù)。Redis內部沒有實現(xiàn)消息拉取這種機制。因此我們需要自己手動編寫代碼去實現(xiàn)這個功能。
在這里我們,我們進一步將消息傳遞再細分為一對一的消息傳遞,多對多的消息傳遞(群組消息傳遞)。
【注:兩個類的代碼相對較多,因此將其折疊起來了】
3、一對一消息傳遞
例子1:一對一消息發(fā)送與獲取
模塊要求:
1、提示有多少個聯(lián)系人發(fā)來新消息
2、信息包含發(fā)送人、時間、信息內容
3、能夠獲取之前的舊消息
4、并且消息能夠保持7天,過期將會被動觸發(fā)刪除
Redis實現(xiàn)思路:
1、新消息與舊消息分別采用兩個鏈表來存儲
2、原始消息的結構采用數(shù)組的形式存放,并且含有發(fā)送人、時間戳、信息內容
3、在推入redis的鏈表前,需要將數(shù)據(jù)轉換為json類型然后再進行存儲
4、在取出新信息時應該使用rpoplpush來實現(xiàn),將已讀的新消息推入舊消息鏈表中
5、取出舊消息時,應該用舊消息的時間與現(xiàn)在的時間進行對比,若超時,則直接刪除后面的全部數(shù)據(jù)(因為數(shù)據(jù)是按時間一個一個壓進鏈表中的,所以對于時間是有序排列的)
數(shù)據(jù)存儲結構圖:
PHP的實現(xiàn)代碼:
#SinglePullMessage.class.php
<?php #單接接收者接收消息 class SinglePullMessage { private $redis=''; #存儲redis對象 /** * @desc 構造函數(shù) * * @param $host string | redis主機 * @param $port int | 端口 */ public function __construct($host,$port=6379) { $this->redis=new Redis(); $this->redis->connect($host,$port); } /** * @desc 發(fā)送消息(一個人) * * @param $toUser string | 接收人 * @param $messageArr array | 發(fā)送的消息數(shù)組,包含sender、message、time * * @return bool */ public function sendSingle($toUser,$messageArr) { $json_message=json_encode($messageArr); #編碼成json數(shù)據(jù) return $this->redis->lpush($toUser,$json_message); #將數(shù)據(jù)推入鏈表 } /** * @desc 用戶獲取新消息 * * @param $user string | 用戶名 * * @return array 返回數(shù)組,包含多少個用戶發(fā)來新消息,以及具體消息 */ public function getNewMessage($user) { #接收新信息數(shù)據(jù),并且將數(shù)據(jù)推入舊信息數(shù)據(jù)鏈表中,并且在原鏈表中刪除 $messageArr=array(); while($json_message=$this->redis->rpoplpush($user, 'preMessage_'.$user)) { $temp=json_decode($json_message); #將json數(shù)據(jù)變成對象 $messageArr[$temp->sender][]=$temp; #轉換成數(shù)組信息 } if($messageArr) { $arr['count']=count($messageArr); #統(tǒng)計有多少個用戶發(fā)來信息 $arr['messageArr']=$messageArr; return $arr; } return false; } public function getPreMessage($user) { ##取出舊消息 $messageArr=array(); $json_pre=$this->redis->lrange('preMessage_'.$user, 0, -1); #一次性將全部舊消息取出來 foreach ($json_pre as $k => $v) { $temp=json_decode($v); #json反編碼 $timeout=$temp->time+60*60*24*7; #數(shù)據(jù)過期時間 七天過期 if($timeout<time()) #判斷數(shù)據(jù)是否過期 { if($k==0) #若是最遲插入的數(shù)據(jù)都過期了,則將所有數(shù)據(jù)刪除 { $this->redis->del('preMessage_'.$user); break; } $this->redis->ltrim('preMessage_'.$user, 0, $k); #若檢測出有過期的,則將比它之前插入的所有數(shù)據(jù)刪除 break; } $messageArr[$temp->sender][]=$temp; } return $messageArr; } /** * @desc 消息處理,沒什么特別的作用。在這里這是用來處理數(shù)組信息,然后將其輸出。 * * @param $arr array | 需要處理的信息數(shù)組 * * @return 返回打印輸出 */ public function dealArr($arr) { foreach ($arr as $k => $v) { foreach ($v as $k1 => $v2) { echo '發(fā)送人:'.$v2->sender.' 發(fā)送時間:'.date('Y-m-d h:i:s',$v2->time).'<br/>'; echo '消息內容:'.$v2->message.'<br/>'; } echo "<hr/>"; } } }