音讯传递

By admin in 4858.com on 2019年7月7日

翻阅目录

1、摘要

  音信传递这一施用普遍存在于种种网址中,那几个作用也是二个网址不可或缺的。常见的消息传递应用有,微博和讯中的@小编啊、给您商量然后的唤起呀、赞赞赞提醒、私信呀、以致是发和讯分享的新鲜事;果壳网中的私信呀、live发送过来的信息、今日头条团队音讯啊等等。

 

开卷目录

1、摘要

  新闻传递这一选拔普及存在于各种网址中,那几个效用也是多少个网址至关重要的。常见的音讯传递应用有,乐乎今日头条中的@笔者呀、给你讨论然后的提醒呀、赞赞赞提醒、私信呀、乃至是发搜狐分享的新人新事;今日头条中的私信呀、live发送过来的新闻、腾讯网团队音信啊等等。

1、摘要

2、达成格局

  音信传递即多个恐怕三个客户端在相互发送和接受新闻。

  平日有二种方法完结:

  第一种为消息推送。Redis内置有这种机制,publish往频道推送新闻、subscribe订阅频道。这种措施有二个毛病便是必须保险接收者时刻在线(便是此时程序不可能停下来,平昔保持监察和控制状态,借使断线后就能并发客户端错过消息)

  第三种为音信拉取。所谓音信拉取,正是客户端自主去取得存款和储蓄在服务器中的数据。Redis内部尚未完结新闻拉取这种体制。由此大家要求自个儿手动编写代码去完结那个意义。

  在那边大家,大家更是将音信传递再细分为一对一的音信传递,多对多的音讯传递(群组音信传递)。

【注:七个类的代码绝对很多,因而将其折叠起来了】

 

  • 1、摘要
  • 2、完毕格局
  • 3、一对一新闻传递
  • 4、多对多音讯传递

2、达成格局

  新闻传递即七个或然几个客户端在竞相发送和接收音信。

  平常有三种方法达成:

  第一种为音信推送。Redis内置有这种机制,publish往频道推送音讯、subscribe订阅频道。这种艺术有四个劣点就是必须确认保证接收者时刻在线(便是此时程序不可能停下来,一贯维持监察和控制情状,借使断线后就能并发客户端遗失新闻)

  第二种为新闻拉取。所谓音信拉取,就是客户端自己作主去赢得存款和储蓄在服务器中的数据。Redis内部尚未落到实处音讯拉取这种体制。因而大家必要团结手动编写代码去落实那个职能。

  在那边我们,我们越来越将新闻传递再细分为一对一的音信传递,多对多的音信传递。

【注:五个类的代码绝对很多,由此将其折叠起来了】

2、达成格局

3、一对一音讯传递

  例子1:一对一新闻发送与收获

  模块须求:

  1、提示有稍许个关系人发来新音讯

  2、音信蕴含发送给外人、时间、音讯内容

  3、能够获得此前的旧音讯

  4、而且消息能够维持7天,过期将会被动触发删除

  Redis完成思路:

  1、新消息与旧信息分别选择八个链表来积累

  2、原始音信的协会采用数组的款式寄存,并且带有发赠给别人、时间戳、音讯内容

  3、在推入redis的链表前,供给将数据转变为json类型然后再拓展仓库储存

  4、在抽取新音讯时应有运用rpoplpush来实现,将已读的新音讯推入旧新闻链表中

  5、抽出旧音信时,应该用旧音讯的年月与现行反革命的年月举办相比较,若超时,则一向删除后边的一体数码(因为数量是按期间二个贰个压进链表中的,所以对于时间是严守原地排列的)

数码存款和储蓄结构图:

 4858.com 1

PHP的兑当代码:

#SinglePullMessage.class.php

4858.com 24858.com 3

  1 <?php
  2 #单接接收者接收消息
  3 class SinglePullMessage
  4 {
  5     private $redis='';  #存储redis对象
  6     /**
  7     * @desc 构造函数
  8     * 
  9     * @param $host string | redis主机
 10     * @param $port int    | 端口
 11     */
 12     public function __construct($host,$port=6379)
 13     {
 14         $this->redis=new Redis();
 15         $this->redis->connect($host,$port);
 16     } 
 17 
 18     /**
 19     * @desc 发送消息(一个人)
 20     * 
 21     * @param $toUser   string    | 接收人
 22     * @param $messageArr array   | 发送的消息数组,包含sender、message、time 
 23     *
 24     * @return bool
 25     */
 26     public function sendSingle($toUser,$messageArr)
 27     {
 28         $json_message=json_encode($messageArr);    #编码成json数据
 29         return $this->redis->lpush($toUser,$json_message);      #将数据推入链表 
 30     }
 31 
 32     /**
 33     * @desc 用户获取新消息
 34     *
 35     * @param $user string | 用户名
 36     *
 37     * @return array 返回数组,包含多少个用户发来新消息,以及具体消息
 38     */
 39     public function getNewMessage($user)
 40     {
 41         #接收新信息数据,并且将数据推入旧信息数据链表中,并且在原链表中删除
 42         $messageArr=array();
 43         while($json_message=$this->redis->rpoplpush($user, 'preMessage_'.$user))
 44         {
 45             $temp=json_decode($json_message);   #将json数据变成对象
 46             $messageArr[$temp->sender][]=$temp;        #转换成数组信息
 47         }
 48         if($messageArr)
 49         {
 50             $arr['count']=count($messageArr);   #统计有多少个用户发来信息
 51             $arr['messageArr']=$messageArr;
 52             return $arr;
 53         }
 54         return false;
 55     }
 56 
 57     public function getPreMessage($user)
 58     {
 59         ##取出旧消息
 60         $messageArr=array();
 61         $json_pre=$this->redis->lrange('preMessage_'.$user, 0, -1);    #一次性将全部旧消息取出来
 62         foreach ($json_pre as $k => $v) 
 63         {
 64             $temp=json_decode($v);            #json反编码
 65             $timeout=$temp->time+60*60*24*7;  #数据过期时间  七天过期
 66             if($timeout<time())               #判断数据是否过期
 67             {
 68                 if($k==0)                     #若是最迟插入的数据都过期了,则将所有数据删除
 69                 {
 70                     $this->redis->del('preMessage_'.$user);
 71                     break;
 72                 }
 73                 $this->redis->ltrim('preMessage_'.$user, 0, $k);  #若检测出有过期的,则将比它之前插入的所有数据删除
 74                 break;
 75             }
 76             $messageArr[$temp->sender][]=$temp;
 77         }
 78         return $messageArr;
 79     }
 80 
 81     /**
 82     * @desc 消息处理,没什么特别的作用。在这里这是用来处理数组信息,然后将其输出。 
 83     *
 84     * @param $arr array | 需要处理的信息数组
 85     *
 86     * @return 返回打印输出
 87     */
 88     public function dealArr($arr)
 89     {
 90         foreach ($arr as $k => $v) 
 91         {
 92             foreach ($v as $k1 => $v2) 
 93             {
 94                 echo '发送人:'.$v2->sender.'    发送时间:'.date('Y-m-d h:i:s',$v2->time).'<br/>';
 95                 echo '消息内容:'.$v2->message.'<br/>';
 96             }
 97             echo "<hr/>";
 98         }
 99     }
100 
101 
102 }

View Code

 

音讯传递。 测试:

  1、发送信息

  #建立test1.php

1 include './SinglePullMessage.class.php';
2 $object=new SinglePullMessage('192.168.95.11');
3 #发送消息
4 $sender='boss';     #发送者
5 $to='jane';         #接收者
6 $message='How are you';    #信息
7 $time=time();
8 $arr=array('sender'=>$sender,'message'=>$message,'time'=>$time);
9 echo $object->sendSingle($to,$arr);

 

  2、获取新消息

  #建立test2.php

 1 include './SinglePullMessage.class.php';
 2 $object=new SinglePullMessage('192.168.95.11');
 3 #获取新消息
 4 $arr=$object->getNewMessage('jane');
 5 if($arr)
 6 {
 7     echo $arr['count']."个联系人发来新消息<br/><hr/>";
 8     $object->dealArr($arr['messageArr']);   
 9 }
10 else
11     echo "无新消息";

 

   访谈结果:

4858.com 4

  3、获取旧音讯

  #建立test3.php

 1 include './SinglePullMessage.class.php';
 2 $object=new SinglePullMessage('192.168.95.11');
 3 #获取旧消息
 4 $arr=$object->getPreMessage('jane');
 5 if($arr)
 6 {
 7     $object->dealArr($arr);
 8 }
 9 else
10     echo "无旧数据";

 

 

 

回来顶端

3、一对一信息传递

  例子1:一对一消息发送与收获

  模块须求:

  1、提醒有微微个挂钩人发来新音信

  2、信息包括发赠与旁人、时间、音讯内容

  3、能够得到在此以前的旧音讯

  4、並且音讯能够维持7天,过期将会被动触发删除

  Redis完成思路:

  1、新音讯与旧音信分别选用七个链表来积攒

  2、原始音信的布局采用数组的款型存放,何况包括发赠与别人、时间戳、消息内容

  3、在推入redis的链表前,要求将数据调换为json类型然后再开始展览仓库储存

  4、在收取新新闻时应有运用rpoplpush来落成,将已读的新新闻推入旧消息链表中

  5、收取旧新闻时,应该用旧音信的时光与现行反革命的年华张开自己检查自纠,若超时,则直接删除后边的满贯数码(因为数量是定时间二个多少个压进链表中的,所以对于时间是铁定的事情排列的)

数量存款和储蓄结构图:

4858.com 5

PHP的达成代码:

#SinglePullMessage.class.php

4858.com 64858.com 7

  1 <?php  2 #单接接收者接收消息  3 class SinglePullMessage  4 {  5     private $redis='';  #存储redis对象  6     /**  7     * @desc 构造函数  8     *   9     * @param $host string | redis主机 10     * @param $port int    | 端口 11     */ 12     public function __construct($host,$port=6379) 13     { 14         $this->redis=new Redis(); 15         $this->redis->connect($host,$port); 16     }  17  18     /** 19     * @desc 发送消息 20     *  21     * @param $toUser   string    | 接收人 22     * @param $messageArr array   | 发送的消息数组,包含sender、message、time  23     * 24     * @return bool 25     */ 26     public function sendSingle($toUser,$messageArr) 27     { 28         $json_message=json_encode($messageArr);    #编码成json数据 29         return $this->redis->lpush($toUser,$json_message);      #将数据推入链表  30     } 31  32     /** 33     * @desc 用户获取新消息 34     * 35     * @param $user string | 用户名 36     * 37     * @return array 返回数组,包含多少个用户发来新消息,以及具体消息 38     */ 39     public function getNewMessage($user) 40     { 41         #接收新信息数据,并且将数据推入旧信息数据链表中,并且在原链表中删除 42         $messageArr=array(); 43         while($json_message=$this->redis->rpoplpush($user, 'preMessage_'.$user)) 44         { 45             $temp=json_decode($json_message);   #将json数据变成对象 46             $messageArr[$temp->sender][]=$temp;        #转换成数组信息 47         } 48         if($messageArr) 49         { 50             $arr['count']=count($messageArr);   #统计有多少个用户发来信息 51             $arr['messageArr']=$messageArr; 52             return $arr; 53         } 54         return false; 55     } 56  57     public function getPreMessage($user) 58     { 59         ##取出旧消息 60         $messageArr=array(); 61         $json_pre=$this->redis->lrange('preMessage_'.$user, 0, -1);    #一次性将全部旧消息取出来 62         foreach ($json_pre as $k => $v)  63         { 64             $temp=json_decode($v);            #json反编码 65             $timeout=$temp->time+60*60*24*7;  #数据过期时间  七天过期 66             if($timeout<time               #判断数据是否过期 67             { 68                 if($k==0)                     #若是最迟插入的数据都过期了,则将所有数据删除 69                 { 70                     $this->redis->del('preMessage_'.$user); 71                     break; 72                 } 73                 $this->redis->ltrim('preMessage_'.$user, 0, $k);  #若检测出有过期的,则将比它之前插入的所有数据删除 74                 break; 75             } 76             $messageArr[$temp->sender][]=$temp; 77         } 78         return $messageArr; 79     } 80  81     /** 82     * @desc 消息处理,没什么特别的作用。在这里这是用来处理数组信息,然后将其输出。  83     * 84     * @param $arr array | 需要处理的信息数组 85     * 86     * @return 返回打印输出 87     */ 88     public function dealArr($arr) 89     { 90         foreach ($arr as $k => $v)  91         { 92             foreach ($v as $k1 => $v2)  93             { 94                 echo '发送人:'.$v2->sender.'    发送时间:'.date('Y-m-d h:i:s',$v2->time).'<br/>'; 95                 echo '消息内容:'.$v2->message.'<br/>'; 96             } 97             echo "<hr/>"; 98         } 99     }100 101 102 }

View Code

测试:

  1、发送新闻

  #建立test1.php

1 include './SinglePullMessage.class.php';2 $object=new SinglePullMessage('192.168.95.11');3 #发送消息4 $sender='boss';     #发送者5 $to='jane';         #接收者6 $message='How are you';    #信息7 $time=time();8 $arr=array('sender'=>$sender,'message'=>$message,'time'=>$time);9 echo $object->sendSingle($to,$arr);

  2、获取新音讯

  #建立test2.php

 1 include './SinglePullMessage.class.php'; 2 $object=new SinglePullMessage('192.168.95.11'); 3 #获取新消息 4 $arr=$object->getNewMessage('jane'); 5 if($arr) 6 { 7     echo $arr['count']."个联系人发来新消息<br/><hr/>"; 8     $object->dealArr($arr['messageArr']);    9 }10 else11     echo "无新消息";

  访问结果:

4858.com 8

  3、获取旧音讯

  #建立test3.php

 1 include './SinglePullMessage.class.php'; 2 $object=new SinglePullMessage('192.168.95.11'); 3 #获取旧消息 4 $arr=$object->getPreMessage('jane'); 5 if($arr) 6 { 7     $object->dealArr($arr); 8 } 9 else10     echo "无旧数据";

3、一对一新闻传递

4、多对多新闻传递

  例子2:多对多新闻发送与收获(就是群组)

  模块供给:

  1、用户能够活动成立群组,并形成群主

  2、群主能够拉人进来作为群组成员、而且能够踢人

  3、用户可以一向退出群组

  4、能够发送音信,每壹个人成员都足以拉撤废息

  5、群组的信息最大容纳量为伍仟条

  6、成员能够拉取新音信,并提示有稍许新音信

  7、成员能够分页获取在此以前已读的旧消息

  。。。。。成效就写那多少个吗,有亟待照旧想练习的校友们能够追加别的职能,比方禁言、无名新闻发送、文件发送等等。

  Redis完毕思路:

   1、群组的音讯以及群组的成员构成选择有序聚焦实行仓库储存。群组音信有序集中的member存款和储蓄用户发送的json数据音讯,score存款和储蓄独一值,将动用原子操作incr获取string中的自拉长值进行仓库储存;群组成员有序聚焦的member存款和储蓄user,score存款和储蓄非零数字(在此间这些score意义一点都不大,笔者的例证代码中使用数字1为群主的score,其余的积存为2。当然那使用这些数据还足以扩张其余成效,比如群组中成员等第)可参看上边数据存款和储蓄结构简图。

  2、用户所出席的群组也是采纳有序聚焦举办仓库储存。当中,member存款和储蓄群组ID,score存储用户已经赢得该群组的最大音讯分值(对应群组音讯的score值)

  3、用户创立群组的时候,通过原子操作incr进而获取二个独一ID

  4、用户在群中发送消息时,也是通过原子操作incr获取多个独一自拉长有序ID

  5、在进行incr时,为防卫出现导致竞争关系,因而供给打开加锁操作【redis详细锁的讲课能够参照:Redis营造遍布式锁】

  6、制造群组方法大致思路,任何二个用户都得以创设群组聊天,在开立的还要,能够挑选时是否充裕群组成员(参数通过数组的款型)。创造进度将会为那一个群建构设构造二个群组成员有序聚集(群组新闻有序聚集暂且不创设),接着将群主增多进去,再将群ID加多用户所参预的群组有序聚聚集。

数据存款和储蓄结构图:

4858.com 9

 

4858.com 10

PHP的代码达成:

#ManyPullMessage.class.php

4858.com 114858.com 12

  1 <?php
  2 class ManyPullMessage
  3 {
  4     private $redis='';  #存储redis对象
  5     /**
  6     * @desc 构造函数
  7     * 
  8     * @param $host string | redis主机
  9     * @param $port int    | 端口
 10     */
 11     public function __construct($host,$port=6379)
 12     {
 13         $this->redis=new Redis();
 14         $this->redis->connect($host,$port);
 15     } 
 16 
 17     /**
 18     * @desc 用于创建群组的方法,在创建的同时还可以拉人进群组
 19     * 
 20     * @param $user   string   | 用户名,创建群组的主人
 21     * @param $addUser array   | 其他用户构成的数组
 22     *
 23     * @param $lockName string | 锁的名字,用于获取群组ID的时候用
 24     * @return int 返回群组ID
 25     */
 26     public function createGroupChat($user, $addUser=array(), $lockName='chatIdLock')
 27     {
 28         $identifier=$this->getLock($lockName);  #获取锁
 29         if($identifier)
 30         {
 31             $id=$this->redis->incr('groupChatID');       #获取群组ID
 32             $this->releaseLock($lockName,$identifier);   #释放锁
 33         }
 34         else
 35             return false;
 36         $messageCount=$this->redis->set('countMessage_'.$id, 0);  #初始化这个群组消息计数器
 37         #开启非事务型流水线,一次性将所有redis命令传给redis,减少与redis的连接
 38         $pipe=$this->redis->pipeline();   
 39         $this->redis->zadd('groupChat_'.$id, 1, $user);  #创建群组成员有序集合,并添加群主
 40         #将这个群组添加到user所参加的群组有序集合中
 41         $this->redis->zadd('hasGroupChat_'.$user, 0, $id);  
 42         foreach ($addUser as $v)    #创建群组的同时需要添加的用户成员
 43         {
 44             $this->redis->zadd('groupChat_'.$id, 2, $v);
 45             $this->redis->zadd('hasGroupChat_'.$v, 0, $id);
 46         }
 47         $pipe->exec();
 48         return $id;    #返回群组ID
 49     }
 50 
 51     /**
 52     * @desc 群主主动拉人进群
 53     *
 54     * @param $user       string | 群主名
 55     * @param $groupChatID   int | 群组ID
 56     * @param $addMembers array  | 需要拉进群的用户
 57     *
 58     * @return bool
 59     */
 60     public function addMembers($user, $groupChatID, $addMembers=array())
 61     {
 62         $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user);  #将groupChatName的群主取出来
 63         if($groupMasterScore==1)     #判断user是否是群主
 64         {
 65             $pipe=$this->redis->pipeline(); #开启非事务流水线
 66             foreach ($addMembers as $v) 
 67             {
 68                 $this->redis->zadd('groupChat_'.$groupChatID, 2, $v);                 #添加进群
 69                 $this->redis->zadd('hasGroupChat_'.$v, 0, $groupChatID); #添加群名到用户的有序集合中
 70             }
 71             $pipe->exec();
 72             return true;
 73         }
 74         return false;
 75     }
 76 
 77     /**
 78     * @desc 群主删除成员
 79     *
 80     * @param $user       string | 群主名
 81     * @param $groupChatID   int | 群组ID
 82     * @param $delMembers  array | 需要删除的成员名字
 83     *
 84     * @return bool
 85     */
 86     public function delMembers($user, $groupChatID, $delMembers=array())
 87     {
 88         $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user); 
 89         if($groupMasterScore==1)     #判断user是否是群主
 90         {
 91             $pipe=$this->redis->pipeline(); #开启非事务流水线
 92             foreach ($delMembers as $v) 
 93             {
 94                 $this->redis->zrem('groupChat_'.$groupChatID, $v);                 
 95                 $this->redis->zrem('hasGroupChat_'.$v, $groupChatID); 
 96             }
 97             $pipe->exec();
 98             return true;
 99         }
100         return false;
101     }
102 
103     /**
104     * @desc 退出群组
105     *
106     * @param $user string     | 用户名
107     * @param $groupChatID int | 群组名
108     */
109     public function quitGroupChat($user, $groupChatID)
110     {
111         $this->redis->zrem('groupChat_'.$groupChatID, $user);
112         $this->redis->zrem('hasGroupChat_'.$user, $groupChatID);
113         return true;
114     }
115 
116     /**
117     * @desc 发送消息
118     *
119     * @param $user string        | 用户名
120     * @param $groupChatID int    | 群组ID
121     * @param $messageArr array   | 包含发送消息的数组
122     * @param $preLockName string | 群消息锁前缀,群消息锁全名为countLock_群ID
123     *
124     * @return bool
125     */
126     public function sendMessage($user, $groupChatID, $messageArr, $preLockName='countLock_')
127     {
128         $memberScore=$this->redis->zscore('groupChat_'.$groupChatID, $user); #成员score
129         if($memberScore)
130         {
131             $identifier=$this->getLock($preLockName.$groupChatID);  #获取锁
132             if($identifier)     #判断获取锁是否成功
133             {
134                 $messageCount=$this->redis->incr('countMessage_'.$groupChatID);
135                 $this->releaseLock($preLockName.$groupChatID,$identifier);  #释放锁
136             }
137             else
138                 return false;
139             $json_message=json_encode($messageArr);
140             $this->redis->zadd('groupChatMessage_'.$groupChatID, $messageCount, $json_message);
141             $count=$this->redis->zcard('groupChatMessage_'.$groupChatID);   #查看信息量大小
142             if($count>5000) #判断数据量有没有达到5000条
143             {   #数据量超5000,则需要清除旧数据
144                 $start=5000-$count;
145                 $this->redis->zremrangebyrank('groupChatMessage_'.$groupChatID, $start, $count);
146             }
147             return true;
148         }
149         return false;
150     }
151 
152     /**
153     * @desc 获取新信息
154     *
155     * @param $user string | 用户名
156     *
157     * @return 成功则放回json数据数组,无新信息返回false
158     */
159     public function getNewMessage($user)
160     {
161         $arrID=$this->redis->zrange('hasGroupChat_'.$user, 0, -1, 'withscores');    #获取用户拥有的群组ID
162         $json_message=array();  #初始化
163         foreach ($arrID as $k => $v)    #遍历循环所有群组,查看是否有新消息
164         {
165             $messageCount=$this->redis->get('countMessage_'.$k);    #群组最大信息分值数
166             if($messageCount>$v)    #判断用户是否存在未读新消息
167             {
168                 $json_message[$k]['message']=$this->redis->zrangebyscore('groupChatMessage_'.$k, $v+1, $messageCount);
169                 $json_message[$k]['count']=count($json_message[$k]['message']);  #统计新消息数量
170                 $this->redis->zadd('hasGroupChat_'.$user, $messageCount, $k);    #更新已获取消息
171             }   
172         }
173         if($json_message)
174             return $json_message;
175         return false;
176     }
177 
178     /**
179     * @desc 分页获取群组信息
180     *
181     * @param $user    string  | 用户名 
182     * @param $groupChatID int | 群组ID
183     * @param $page        int | 第几页
184     * @param $size        int | 每页多少条数据
185     *
186     * @return 成功返回json数据,失败返回false
187     */
188     public function getPartMessage($user, $groupChatID, $page=1, $size=10)
189     {
190         $start=$page*$size-$size;   #开始截取数据位置
191         $stop=$page*$size-1;        #结束截取数据位置
192         $json_message=$this->redis->zrevrange('groupChatMessage_'.$groupChatID, $start, $stop);
193         if($json_message)
194             return $json_message;
195         return false;
196     }
197 
198 
199     /**
200     * @desc 加锁方法
201     *
202     * @param $lockName string | 锁的名字
203     * @param $timeout int | 锁的过期时间
204     *
205     * @return 成功返回identifier/失败返回false
206     */
207     public function getLock($lockName, $timeout=2)
208     {
209         $identifier=uniqid();       #获取唯一标识符
210         $timeout=ceil($timeout);    #确保是整数
211         $end=time()+$timeout;
212         while(time()<$end)          #循环获取锁
213         {
214             /*
215             #这里的set操作可以等同于下面那个if操作,并且可以减少一次与redis通讯
216             if($this->redis->set($lockName, $identifier array('nx', 'ex'=>$timeout)))
217                 return $identifier;
218             */
219             if($this->redis->setnx($lockName, $identifier))    #查看$lockName是否被上锁
220             {
221                 $this->redis->expire($lockName, $timeout);     #为$lockName设置过期时间
222                 return $identifier;                             #返回一维标识符
223             }
224             elseif ($this->redis->ttl($lockName)===-1) 
225             {
226                 $this->redis->expire($lockName, $timeout);     #检测是否有设置过期时间,没有则加上
227             }
228             usleep(0.001);         #停止0.001ms
229         }
230         return false;
231     }
232 
233     /**
234     * @desc 释放锁
235     *
236     * @param $lockName string   | 锁名
237     * @param $identifier string | 锁的唯一值
238     *
239     * @param bool
240     */
241     public function releaseLock($lockName,$identifier)
242     {
243         if($this->redis->get($lockName)==$identifier)   #判断是锁有没有被其他客户端修改
244         { 
245             $this->redis->multi();
246             $this->redis->del($lockName);   #释放锁
247             $this->redis->exec();
248             return true;
249         }
250         else
251         {
252             return false;   #其他客户端修改了锁,不能删除别人的锁
253         }
254     }
255 
256 
257 }
258 
259 ?>

View Code

 

测试:

  1、创建createGroupChat.php(测量试验创立群组功效)

  施行代码并创造568、569群组(群主为jack)

1 include './ManyPullMessage.class.php';
2 $object=new ManyPullMessage('192.168.95.11');
3 #创建群组
4 $user='jack';
5 $arr=array('jane1','jane2');
6 $a=$object->createGroupChat($user,$arr);
7 echo "<pre>";
8 print_r($a);
9 echo "</pre>";die;

 

4858.com 13 

4858.com 14

 

  2、建构addMembers.php(测验增加成员功效)

  试行代码并加多新成员

1 include './ManyPullMessage.class.php';
2 $object=new ManyPullMessage('192.168.95.11');
3 $b=$object->addMembers('jack','568',array('jane1','jane2','jane3','jane4'));
4 echo "<pre>";
5 print_r($b);
6 echo "</pre>";die;

4858.com 15

  3、创设delete.php(测验群主删除成员功用)

1 include './ManyPullMessage.class.php';
2 $object=new ManyPullMessage('192.168.95.11');
3 #群主删除成员
4 $c=$object->delMembers('jack', '568', array('jane1','jane4'));
5 echo "<pre>";
6 print_r($c);
7 echo "</pre>";die;

4858.com 16

  4、构造建设sendMessage.php(测量试验发送音讯功效)

  多实行两回,568、569都发几条

 1 include './ManyPullMessage.class.php';
 2 $object=new ManyPullMessage('192.168.95.11');
 3 #发送消息
 4 $user='jane2';
 5 $message='go go go';
 6 $groupChatID=568;
 7 $arr=array('sender'=>$user, 'message'=>$message, 'time'=>time());
 8 $d=$object->sendMessage($user,$groupChatID,$arr);
 9 echo "<pre>";
10 print_r($d);
11 echo "</pre>";die;

 

4858.com 17

4858.com 18

  5、创设getNewMessage.php(测量检验用户获得新新闻效率)

1 include './ManyPullMessage.class.php';
2 $object=new ManyPullMessage('192.168.95.11');
3 #用户获取新消息
4 $e=$object->getNewMessage('jane2');
5 echo "<pre>";
6 print_r($e);
7 echo "</pre>";die;

 

4858.com 19

  6、建立getPartMessage.php(测量检验用户获得某些群组部分新闻)

  (多发送几条新闻,用于测量试验。568国共18条数据)

1 include './ManyPullMessage.class.php';
2 $object=new ManyPullMessage('192.168.95.11');
3 #用户获取某个群组部分消息
4 $f=$object->getPartMessage('jane2', 568, 1, 10); 
5 echo "<pre>";
6 print_r($f);
7 echo "</pre>";die;

 

page=1,size=10

4858.com 20

page=2,size=10

4858.com 21

测量检验停止,还亟需别的功用能够和睦进行修改增多测量检验。

此番整治那篇小说相对相比较赶,心里早就想着快点整理完赶紧学习别的的本领啦,哈哈22333。各位大神请留步,恳请各位给点学习redis的点拨意见,本身工作偏向是PHP

 

(以上是友善的片段观点,若有欠缺或然失实的地点请各位提议)

作者:那一叶随风

 注脚:本博客作品为原创,只代表自身在专门的学业学习中某不经常间内计算的思想或结论。转载时请在文章页面明显地方给出原著链接

 

1、摘要

  新闻传递这一利用遍布存在于各种网址中,那么些效果也是一个网址不可或缺的。常见的新闻传递应用有,网易和讯中的@小编哟、给你批评然后的唤醒呀、赞赞赞提示、私信呀、以致是发今日头条分享的新人新事;网易中的私信呀、live发送过来的音信、乐乎团队消息啊等等。

归来顶上部分

4、多对多新闻传递

  例子2:多对多音讯发送与收获

  模块供给:

  1、用户能够自行创立群组,并变为群主

  2、群主能够拉人进来作为群组成员、并且能够踢人

  3、用户能够一贯退出群组

  4、能够发送音讯,各个人成员都得以拉取新闻

  5、群组的新闻最大容纳量为四千条

  6、成员能够拉取新信息,并提示有稍许新新闻

  7、成员能够分页获取在此以前已读的旧音讯

  。。。。。作用就写那多少个吗,有亟待依旧想练习的同学们方可扩充其余职能,比如禁言、佚名音信发送、文件发送等等。

  Redis实现思路:

   1、群组的音信以及群组的分子构成接纳有序集中实行仓库储存。群组新闻有序聚焦的member存款和储蓄用户发送的json数据新闻,score存款和储蓄独一值,将接纳原子操作incr获取string中的自增加值实行仓库储存;群组成员有序聚焦的member存储user,score存款和储蓄非零数字(在那边这么些score意义相当的小,俺的事例代码中动用数字1为群主的score,别的的仓库储存为2。当然那使用那个数目还足以扩大别的作用,比方群组中成员等级)可参照他事他说加以考察上面数据存款和储蓄结构简图。

  2、用户所投入的群组也是运用有序集中实行仓库储存。在这之中,member存储群组ID,score存款和储蓄用户已经获得该群组的最大音信分值(对应群组消息的score值)

  3、用户创设群组的时候,通过原子操作incr进而获取叁个独一ID

  4、用户在群中发送消息时,也是透过原子操作incr获取贰个独一自增加平稳ID

  5、在实践incr时,为幸免出现导致竞争关系,因此须要展开加锁操作【redis详细锁的疏解能够参照:Redis营造分布式锁

  6、创设群组方法轻便思路,任何三个用户都能够创立群组聊天,在创设的还要,能够挑选时是或不是丰裕群组成员(参数通过数组的格局)。创造进度将会为那一个群组创立三个群组成员有序聚焦(群组音讯有序聚焦临时不创设),接着将群主增添进去,再将群ID增添用户所参预的群组有序聚聚集。

多少存款和储蓄结构图:

4858.com 22

4858.com 23

PHP的代码完成:

#ManyPullMessage.class.php

4858.com 244858.com 25

  1 <?php  2 class ManyPullMessage  3 {  4     private $redis='';  #存储redis对象  5     /**  6     * @desc 构造函数  7     *   8     * @param $host string | redis主机  9     * @param $port int    | 端口 10     */ 11     public function __construct($host,$port=6379) 12     { 13         $this->redis=new Redis(); 14         $this->redis->connect($host,$port); 15     }  16  17     /** 18     * @desc 用于创建群组的方法,在创建的同时还可以拉人进群组 19     *  20     * @param $user   string   | 用户名,创建群组的主人 21     * @param $addUser array   | 其他用户构成的数组 22     * 23     * @param $lockName string | 锁的名字,用于获取群组ID的时候用 24     * @return int 返回群组ID 25     */ 26     public function createGroupChat($user, $addUser=array(), $lockName='chatIdLock') 27     { 28         $identifier=$this->getLock($lockName);  #获取锁 29         if($identifier) 30         { 31             $id=$this->redis->incr('groupChatID');       #获取群组ID 32             $this->releaseLock($lockName,$identifier);   #释放锁 33         } 34         else 35             return false; 36         $messageCount=$this->redis->set('countMessage_'.$id, 0);  #初始化这个群组消息计数器 37         #开启非事务型流水线,一次性将所有redis命令传给redis,减少与redis的连接 38         $pipe=$this->redis->pipeline();    39         $this->redis->zadd('groupChat_'.$id, 1, $user);  #创建群组成员有序集合,并添加群主 40         #将这个群组添加到user所参加的群组有序集合中 41         $this->redis->zadd('hasGroupChat_'.$user, 0, $id);   42         foreach ($addUser as $v)    #创建群组的同时需要添加的用户成员 43         { 44             $this->redis->zadd('groupChat_'.$id, 2, $v); 45             $this->redis->zadd('hasGroupChat_'.$v, 0, $id); 46         } 47         $pipe->exec(); 48         return $id;    #返回群组ID 49     } 50  51     /** 52     * @desc 群主主动拉人进群 53     * 54     * @param $user       string | 群主名 55     * @param $groupChatID   int | 群组ID 56     * @param $addMembers array  | 需要拉进群的用户 57     * 58     * @return bool 59     */ 60     public function addMembers($user, $groupChatID, $addMembers=array 61     { 62         $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user);  #将groupChatName的群主取出来 63         if($groupMasterScore==1)     #判断user是否是群主 64         { 65             $pipe=$this->redis->pipeline(); #开启非事务流水线 66             foreach ($addMembers as $v)  67             { 68                 $this->redis->zadd('groupChat_'.$groupChatID, 2, $v);                 #添加进群 69                 $this->redis->zadd('hasGroupChat_'.$v, 0, $groupChatID); #添加群名到用户的有序集合中 70             } 71             $pipe->exec(); 72             return true; 73         } 74         return false; 75     } 76  77     /** 78     * @desc 群主删除成员 79     * 80     * @param $user       string | 群主名 81     * @param $groupChatID   int | 群组ID 82     * @param $delMembers  array | 需要删除的成员名字 83     * 84     * @return bool 85     */ 86     public function delMembers($user, $groupChatID, $delMembers=array 87     { 88         $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user);  89         if($groupMasterScore==1)     #判断user是否是群主 90         { 91             $pipe=$this->redis->pipeline(); #开启非事务流水线 92             foreach ($delMembers as $v)  93             { 94                 $this->redis->zrem('groupChat_'.$groupChatID, $v);                  95                 $this->redis->zrem('hasGroupChat_'.$v, $groupChatID);  96             } 97             $pipe->exec(); 98             return true; 99         }100         return false;101     }102 103     /**104     * @desc 退出群组105     *106     * @param $user string     | 用户名107     * @param $groupChatID int | 群组名108     */109     public function quitGroupChat($user, $groupChatID)110     {111         $this->redis->zrem('groupChat_'.$groupChatID, $user);112         $this->redis->zrem('hasGroupChat_'.$user, $groupChatID);113         return true;114     }115 116     /**117     * @desc 发送消息118     *119     * @param $user string        | 用户名120     * @param $groupChatID int    | 群组ID121     * @param $messageArr array   | 包含发送消息的数组122     * @param $preLockName string | 群消息锁前缀,群消息锁全名为countLock_群ID123     *124     * @return bool125     */126     public function sendMessage($user, $groupChatID, $messageArr, $preLockName='countLock_')127     {128         $memberScore=$this->redis->zscore('groupChat_'.$groupChatID, $user); #成员score129         if($memberScore)130         {131             $identifier=$this->getLock($preLockName.$groupChatID);  #获取锁132             if($identifier)     #判断获取锁是否成功133             {134                 $messageCount=$this->redis->incr('countMessage_'.$groupChatID);135                 $this->releaseLock($preLockName.$groupChatID,$identifier);  #释放锁136             }137             else138                 return false;139             $json_message=json_encode($messageArr);140             $this->redis->zadd('groupChatMessage_'.$groupChatID, $messageCount, $json_message);141             $count=$this->redis->zcard('groupChatMessage_'.$groupChatID);   #查看信息量大小142             if($count>5000) #判断数据量有没有达到5000条143             {   #数据量超5000,则需要清除旧数据144                 $start=5000-$count;145                 $this->redis->zremrangebyrank('groupChatMessage_'.$groupChatID, $start, $count);146             }147             return true;148         }149         return false;150     }151 152     /**153     * @desc 获取新信息154     *155     * @param $user string | 用户名156     *157     * @return 成功则放回json数据数组,无新信息返回false158     */159     public function getNewMessage($user)160     {161         $arrID=$this->redis->zrange('hasGroupChat_'.$user, 0, -1, 'withscores');    #获取用户拥有的群组ID162         $json_message=array();  #初始化163         foreach ($arrID as $k => $v)    #遍历循环所有群组,查看是否有新消息164         {165             $messageCount=$this->redis->get('countMessage_'.$k);    #群组最大信息分值数166             if($messageCount>$v)    #判断用户是否存在未读新消息167             {168                 $json_message[$k]['message']=$this->redis->zrangebyscore('groupChatMessage_'.$k, $v+1, $messageCount);169                 $json_message[$k]['count']=count($json_message[$k]['message']);  #统计新消息数量170                 $this->redis->zadd('hasGroupChat_'.$user, $messageCount, $k);    #更新已获取消息171             }   172         }173         if($json_message)174             return $json_message;175         return false;176     }177 178     /**179     * @desc 分页获取群组信息180     *181     * @param $user    string  | 用户名 182     * @param $groupChatID int | 群组ID183     * @param $page        int | 第几页184     * @param $size        int | 每页多少条数据185     *186     * @return 成功返回json数据,失败返回false187     */188     public function getPartMessage($user, $groupChatID, $page=1, $size=10)189     {190         $start=$page*$size-$size;   #开始截取数据位置191         $stop=$page*$size-1;        #结束截取数据位置192         $json_message=$this->redis->zrevrange('groupChatMessage_'.$groupChatID, $start, $stop);193         if($json_message)194             return $json_message;195         return false;196     }197 198 199     /**200     * @desc 加锁方法201     *202     * @param $lockName string | 锁的名字203     * @param $timeout int | 锁的过期时间204     *205     * @return 成功返回identifier/失败返回false206     */207     public function getLock($lockName, $timeout=2)208     {209         $identifier=uniqid();       #获取唯一标识符210         $timeout=ceil($timeout);    #确保是整数211         $end=time()+$timeout;212         while(time()<$end)          #循环获取锁213         {214             /*215             #这里的set操作可以等同于下面那个if操作,并且可以减少一次与redis通讯216             if($this->redis->set($lockName, $identifier array('nx', 'ex'=>$timeout)))217                 return $identifier;218             */219             if($this->redis->setnx($lockName, $identifier))    #查看$lockName是否被上锁220             {221                 $this->redis->expire($lockName, $timeout);     #为$lockName设置过期时间222                 return $identifier;                             #返回一维标识符223             }224             elseif ($this->redis->ttl($lockName)===-1) 225             {226                 $this->redis->expire($lockName, $timeout);     #检测是否有设置过期时间,没有则加上227             }228             usleep;         #停止0.001ms229         }230         return false;231     }232 233     /**234     * @desc 释放锁235     *236     * @param $lockName string   | 锁名237     * @param $identifier string | 锁的唯一值238     *239     * @param bool240     */241     public function releaseLock($lockName,$identifier)242     {243         if($this->redis->get($lockName)==$identifier)   #判断是锁有没有被其他客户端修改244         { 245             $this->redis->multi();246             $this->redis->del($lockName);   #释放锁247             $this->redis->exec();248             return true;249         }250         else251         {252             return false;   #其他客户端修改了锁,不能删除别人的锁253         }254     }255 256 257 }258 259 ?>

View Code

测试:

  1、建立createGroupChat.php

  试行代码并创建568、569群组

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #创建群组4 $user='jack';5 $arr=array('jane1','jane2');6 $a=$object->createGroupChat($user,$arr);7 echo "<pre>";8 print_r($a);9 echo "</pre>";die;

4858.com 26

4858.com 27

  2、建立addMembers.php

  施行代码并加多新成员

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 $b=$object->addMembers('jack','568',array('jane1','jane2','jane3','jane4'));4 echo "<pre>";5 print_r($b);6 echo "</pre>";die;

4858.com 28

  3、建设构造delete.php(测验群主删除成员作用)

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #群主删除成员4 $c=$object->delMembers('jack', '568', array('jane1','jane4'));5 echo "<pre>";6 print_r($c);7 echo "</pre>";die;

4858.com 29

  4、建立sendMessage.php

  多推行四遍,568、569都发几条

 1 include './ManyPullMessage.class.php'; 2 $object=new ManyPullMessage('192.168.95.11'); 3 #发送消息 4 $user='jane2'; 5 $message='go go go'; 6 $groupChatID=568; 7 $arr=array('sender'=>$user, 'message'=>$message, 'time'=>time; 8 $d=$object->sendMessage($user,$groupChatID,$arr); 9 echo "<pre>";10 print_r($d);11 echo "</pre>";die;

4858.com 30

4858.com 31

  5、建构getNewMessage.php(测量试验用户得到新新闻作用)

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #用户获取新消息4 $e=$object->getNewMessage('jane2');5 echo "<pre>";6 print_r($e);7 echo "</pre>";die;

4858.com 32

  6、创建getPartMessage.php(测量试验用户获得某些群组部分消息)

  (多发送几条消息,用于测量检验。568国共18条数据)

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #用户获取某个群组部分消息4 $f=$object->getPartMessage('jane2', 568, 1, 10); 5 echo "<pre>";6 print_r($f);7 echo "</pre>";die;

page=1,size=10

4858.com 33

page=2,size=10

4858.com 34

测验停止,还亟需别的效能能够自个儿进行修改增加测验。

这一次整治那篇小说绝对相比赶,心里已经想着快点整理完赶紧学习其余的技艺啦,哈哈22333。各位大神请留步,恳请各位给点学习redis的教导意见,自个儿工作偏侧是PHP

(以上是投机的一些视角,若有不足也许失实的地点请各位建议)

宣示:本博客文章为原创,只象征本人在干活学习中某不常间内计算的观念或结论。转发时请在篇章页面明显地点给出原来的小说链接

4、多对多新闻传递

2、达成格局

  音信传递即多个可能三个客户端在竞相发送和抽取新闻。

  平时有三种艺术达成:

  第一种为消息推送。Redis内置有这种机制,publish往频道推送音讯、subscribe订阅频道。这种形式有三个欠缺就是必须保险接收者时刻在线(正是此时先后不可能停下来,一直维持监察和控制状态,若是断线后就能够冒出客户端丢失音信)

  第两种为音讯拉取。所谓音信拉取,正是客户端自己作主去赢得存款和储蓄在服务器中的数据。Redis内部从不兑现新闻拉取这种机制。因而我们须求和煦手动编写代码去贯彻那些效应。

  在此间我们,大家进一步将新闻传递再细分为一对一的音讯传递,多对多的音讯传递。

【注:多个类的代码相对比较多,由此将其折叠起来了】

再次来到最上端

1、摘要

3、一对一新闻传递

  例子1:一对一新闻发送与收获

  模块供给:

  1、提醒有微微个关系人发来新新闻

  2、消息包涵发送给别人、时间、音信内容

  3、能够获取从前的旧音信

  4、並且音讯能够保持7天,过期将会被动触发删除

  Redis达成思路:

  1、新消息与旧音信分别选拔三个链表来存款和储蓄

  2、原始音信的组织选择数组的款式寄存,而且带有发送给别人、时间戳、音讯内容

  3、在推入redis的链表前,必要将数据转变为json类型然后再拓展仓库储存

  4、在收取新消息时应当利用rpoplpush来达成,将已读的新消息推入旧音信链表中

  5、收取旧新闻时,应该用旧新闻的时刻与今后的时日开始展览对照,若超时,则直接删除后边的总体数额(因为数量是定时间二个贰个压进链表中的,所以对于时间是平稳排列的)

数据存款和储蓄结构图:

4858.com 35

PHP的落到实处代码:

#SinglePullMessage.class.php

4858.com 364858.com 37

  1 <?php  2 #单接接收者接收消息  3 class SinglePullMessage  4 {  5     private $redis='';  #存储redis对象  6     /**  7     * @desc 构造函数  8     *   9     * @param $host string | redis主机 10     * @param $port int    | 端口 11     */ 12     public function __construct($host,$port=6379) 13     { 14         $this->redis=new Redis(); 15         $this->redis->connect($host,$port); 16     }  17  18     /** 19     * @desc 发送消息 20     *  21     * @param $toUser   string    | 接收人 22     * @param $messageArr array   | 发送的消息数组,包含sender、message、time  23     * 24     * @return bool 25     */ 26     public function sendSingle($toUser,$messageArr) 27     { 28         $json_message=json_encode($messageArr);    #编码成json数据 29         return $this->redis->lpush($toUser,$json_message);      #将数据推入链表  30     } 31  32     /** 33     * @desc 用户获取新消息 34     * 35     * @param $user string | 用户名 36     * 37     * @return array 返回数组,包含多少个用户发来新消息,以及具体消息 38     */ 39     public function getNewMessage($user) 40     { 41         #接收新信息数据,并且将数据推入旧信息数据链表中,并且在原链表中删除 42         $messageArr=array(); 43         while($json_message=$this->redis->rpoplpush($user, 'preMessage_'.$user)) 44         { 45             $temp=json_decode($json_message);   #将json数据变成对象 46             $messageArr[$temp->sender][]=$temp;        #转换成数组信息 47         } 48         if($messageArr) 49         { 50             $arr['count']=count($messageArr);   #统计有多少个用户发来信息 51             $arr['messageArr']=$messageArr; 52             return $arr; 53         } 54         return false; 55     } 56  57     public function getPreMessage($user) 58     { 59         ##取出旧消息 60         $messageArr=array(); 61         $json_pre=$this->redis->lrange('preMessage_'.$user, 0, -1);    #一次性将全部旧消息取出来 62         foreach ($json_pre as $k => $v)  63         { 64             $temp=json_decode($v);            #json反编码 65             $timeout=$temp->time+60*60*24*7;  #数据过期时间  七天过期 66             if($timeout<time               #判断数据是否过期 67             { 68                 if($k==0)                     #若是最迟插入的数据都过期了,则将所有数据删除 69                 { 70                     $this->redis->del('preMessage_'.$user); 71                     break; 72                 } 73                 $this->redis->ltrim('preMessage_'.$user, 0, $k);  #若检测出有过期的,则将比它之前插入的所有数据删除 74                 break; 75             } 76             $messageArr[$temp->sender][]=$temp; 77         } 78         return $messageArr; 79     } 80  81     /** 82     * @desc 消息处理,没什么特别的作用。在这里这是用来处理数组信息,然后将其输出。  83     * 84     * @param $arr array | 需要处理的信息数组 85     * 86     * @return 返回打印输出 87     */ 88     public function dealArr($arr) 89     { 90         foreach ($arr as $k => $v)  91         { 92             foreach ($v as $k1 => $v2)  93             { 94                 echo '发送人:'.$v2->sender.'    发送时间:'.date('Y-m-d h:i:s',$v2->time).'<br/>'; 95                 echo '消息内容:'.$v2->message.'<br/>'; 96             } 97             echo "<hr/>"; 98         } 99     }100 101 102 }

View Code

测试:

  1、发送音讯

  #建立test1.php

4858.com 38

1 include './SinglePullMessage.class.php';2 $object=new SinglePullMessage('192.168.95.11');3 #发送消息4 $sender='boss';     #发送者5 $to='jane';         #接收者6 $message='How are you';    #信息7 $time=time();8 $arr=array('sender'=>$sender,'message'=>$message,'time'=>$time);9 echo $object->sendSingle($to,$arr);

4858.com 39

  2、获取新音讯

  #建立test2.php

4858.com 40

 1 include './SinglePullMessage.class.php'; 2 $object=new SinglePullMessage('192.168.95.11'); 3 #获取新消息 4 $arr=$object->getNewMessage('jane'); 5 if($arr) 6 { 7     echo $arr['count']."个联系人发来新消息<br/><hr/>"; 8     $object->dealArr($arr['messageArr']);    9 }10 else11     echo "无新消息";

4858.com 41

  访谈结果:

4858.com 42

  3、获取旧音信

  #建立test3.php

4858.com 43

 1 include './SinglePullMessage.class.php'; 2 $object=new SinglePullMessage('192.168.95.11'); 3 #获取旧消息 4 $arr=$object->getPreMessage('jane'); 5 if($arr) 6 { 7     $object->dealArr($arr); 8 } 9 else10     echo "无旧数据";

4858.com 44回来顶端

新闻传递这一利用分布存在于种种网址中,这几个职能也是贰个网址不可缺少的。常见的音讯传递应用有,天涯论坛新浪中的@小编啊、给你商酌然后的唤起呀、赞赞赞提醒、私信呀、甚至是发微博分享的新人新事;网易中的私信呀、live发送过来的音信、搜狐团队音讯啊等等。

4、多对多音讯传递

  例子2:多对多新闻发送与收获

  模块必要:

  1、用户能够自行成立群组,并产生群主

  2、群主能够推人进来作为群组成员、并且能够踢人

  3、用户能够直接退出群组

  4、能够发送音讯,每一位成员都得以拉取新闻

  5、群组的消息最大容纳量为陆仟条

  6、成员可以拉取新新闻,并指示有微微新新闻

  7、成员能够分页获取以前已读的旧音讯

  。。。。。功效就写那多少个呢,有亟待只怕想演练的同窗们方可追加别的功效,举例禁言、无名新闻发送、文件发送等等。

  Redis实现思路:

   1、群组的音信以及群组的积极分子组成采纳有序集中实行仓库储存。群组消息有序聚焦的member存款和储蓄用户发送的json数据音信,score存款和储蓄独一值,将运用原子操作incr获取string中的自增进值举办仓库储存;群组成员有序聚集的member存款和储蓄user,score存款和储蓄非零数字(在那边这么些score意义非常的小,小编的例证代码中采取数字1为群主的score,别的的存款和储蓄为2。当然那使用那些数据还足以扩大别的功用,比如群组中成员品级)可参照下边数据存款和储蓄结构简图。

  2、用户所参预的群组也是运用有序聚集进行仓库储存。在那之中,member存款和储蓄群组ID,score存款和储蓄用户已经赢得该群组的最大音讯分值(对应群组新闻的score值)

  3、用户创立群组的时候,通过原子操作incr进而获取多个独一ID

  4、用户在群中发送音讯时,也是经过原子操作incr获取一个独一自增进有序ID

  5、在实施incr时,为防范出现导致竞争关系,因而供给进行加锁操作【redis详细锁的教师能够参见:Redis营造遍布式锁

  6、成立群组方法大致思路,任何一个用户都足以创制群组聊天,在开创的还要,能够选择时是否丰硕群组成员(参数通过数组的样式)。创设进程将会为那一个群组建立一个群组成员有序集中(群组音讯有序聚焦一时半刻不创立),接着将群主加多进去,再将群ID加多用户所参与的群组有序聚聚焦。

多少存款和储蓄结构图:

4858.com 45

4858.com 46

PHP的代码完结:

#ManyPullMessage.class.php

4858.com 474858.com 48

  1 <?php  2 class ManyPullMessage  3 {  4     private $redis='';  #存储redis对象  5     /**  6     * @desc 构造函数  7     *   8     * @param $host string | redis主机  9     * @param $port int    | 端口 10     */ 11     public function __construct($host,$port=6379) 12     { 13         $this->redis=new Redis(); 14         $this->redis->connect($host,$port); 15     }  16  17     /** 18     * @desc 用于创建群组的方法,在创建的同时还可以拉人进群组 19     *  20     * @param $user   string   | 用户名,创建群组的主人 21     * @param $addUser array   | 其他用户构成的数组 22     * 23     * @param $lockName string | 锁的名字,用于获取群组ID的时候用 24     * @return int 返回群组ID 25     */ 26     public function createGroupChat($user, $addUser=array(), $lockName='chatIdLock') 27     { 28         $identifier=$this->getLock($lockName);  #获取锁 29         if($identifier) 30         { 31             $id=$this->redis->incr('groupChatID');       #获取群组ID 32             $this->releaseLock($lockName,$identifier);   #释放锁 33         } 34         else 35             return false; 36         $messageCount=$this->redis->set('countMessage_'.$id, 0);  #初始化这个群组消息计数器 37         #开启非事务型流水线,一次性将所有redis命令传给redis,减少与redis的连接 38         $pipe=$this->redis->pipeline();    39         $this->redis->zadd('groupChat_'.$id, 1, $user);  #创建群组成员有序集合,并添加群主 40         #将这个群组添加到user所参加的群组有序集合中 41         $this->redis->zadd('hasGroupChat_'.$user, 0, $id);   42         foreach ($addUser as $v)    #创建群组的同时需要添加的用户成员 43         { 44             $this->redis->zadd('groupChat_'.$id, 2, $v); 45             $this->redis->zadd('hasGroupChat_'.$v, 0, $id); 46         } 47         $pipe->exec(); 48         return $id;    #返回群组ID 49     } 50  51     /** 52     * @desc 群主主动拉人进群 53     * 54     * @param $user       string | 群主名 55     * @param $groupChatID   int | 群组ID 56     * @param $addMembers array  | 需要拉进群的用户 57     * 58     * @return bool 59     */ 60     public function addMembers($user, $groupChatID, $addMembers=array 61     { 62         $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user);  #将groupChatName的群主取出来 63         if($groupMasterScore==1)     #判断user是否是群主 64         { 65             $pipe=$this->redis->pipeline(); #开启非事务流水线 66             foreach ($addMembers as $v)  67             { 68                 $this->redis->zadd('groupChat_'.$groupChatID, 2, $v);                 #添加进群 69                 $this->redis->zadd('hasGroupChat_'.$v, 0, $groupChatID); #添加群名到用户的有序集合中 70             } 71             $pipe->exec(); 72             return true; 73         } 74         return false; 75     } 76  77     /** 78     * @desc 群主删除成员 79     * 80     * @param $user       string | 群主名 81     * @param $groupChatID   int | 群组ID 82     * @param $delMembers  array | 需要删除的成员名字 83     * 84     * @return bool 85     */ 86     public function delMembers($user, $groupChatID, $delMembers=array 87     { 88         $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user);  89         if($groupMasterScore==1)     #判断user是否是群主 90         { 91             $pipe=$this->redis->pipeline(); #开启非事务流水线 92             foreach ($delMembers as $v)  93             { 94                 $this->redis->zrem('groupChat_'.$groupChatID, $v);                  95                 $this->redis->zrem('hasGroupChat_'.$v, $groupChatID);  96             } 97             $pipe->exec(); 98             return true; 99         }100         return false;101     }102 103     /**104     * @desc 退出群组105     *106     * @param $user string     | 用户名107     * @param $groupChatID int | 群组名108     */109     public function quitGroupChat($user, $groupChatID)110     {111         $this->redis->zrem('groupChat_'.$groupChatID, $user);112         $this->redis->zrem('hasGroupChat_'.$user, $groupChatID);113         return true;114     }115 116     /**117     * @desc 发送消息118     *119     * @param $user string        | 用户名120     * @param $groupChatID int    | 群组ID121     * @param $messageArr array   | 包含发送消息的数组122     * @param $preLockName string | 群消息锁前缀,群消息锁全名为countLock_群ID123     *124     * @return bool125     */126     public function sendMessage($user, $groupChatID, $messageArr, $preLockName='countLock_')127     {128         $memberScore=$this->redis->zscore('groupChat_'.$groupChatID, $user); #成员score129         if($memberScore)130         {131             $identifier=$this->getLock($preLockName.$groupChatID);  #获取锁132             if($identifier)     #判断获取锁是否成功133             {134                 $messageCount=$this->redis->incr('countMessage_'.$groupChatID);135                 $this->releaseLock($preLockName.$groupChatID,$identifier);  #释放锁136             }137             else138                 return false;139             $json_message=json_encode($messageArr);140             $this->redis->zadd('groupChatMessage_'.$groupChatID, $messageCount, $json_message);141             $count=$this->redis->zcard('groupChatMessage_'.$groupChatID);   #查看信息量大小142             if($count>5000) #判断数据量有没有达到5000条143             {   #数据量超5000,则需要清除旧数据144                 $start=5000-$count;145                 $this->redis->zremrangebyrank('groupChatMessage_'.$groupChatID, $start, $count);146             }147             return true;148         }149         return false;150     }151 152     /**153     * @desc 获取新信息154     *155     * @param $user string | 用户名156     *157     * @return 成功则放回json数据数组,无新信息返回false158     */159     public function getNewMessage($user)160     {161         $arrID=$this->redis->zrange('hasGroupChat_'.$user, 0, -1, 'withscores');    #获取用户拥有的群组ID162         $json_message=array();  #初始化163         foreach ($arrID as $k => $v)    #遍历循环所有群组,查看是否有新消息164         {165             $messageCount=$this->redis->get('countMessage_'.$k);    #群组最大信息分值数166             if($messageCount>$v)    #判断用户是否存在未读新消息167             {168                 $json_message[$k]['message']=$this->redis->zrangebyscore('groupChatMessage_'.$k, $v+1, $messageCount);169                 $json_message[$k]['count']=count($json_message[$k]['message']);  #统计新消息数量170                 $this->redis->zadd('hasGroupChat_'.$user, $messageCount, $k);    #更新已获取消息171             }   172         }173         if($json_message)174             return $json_message;175         return false;176     }177 178     /**179     * @desc 分页获取群组信息180     *181     * @param $user    string  | 用户名 182     * @param $groupChatID int | 群组ID183     * @param $page        int | 第几页184     * @param $size        int | 每页多少条数据185     *186     * @return 成功返回json数据,失败返回false187     */188     public function getPartMessage($user, $groupChatID, $page=1, $size=10)189     {190         $start=$page*$size-$size;   #开始截取数据位置191         $stop=$page*$size-1;        #结束截取数据位置192         $json_message=$this->redis->zrevrange('groupChatMessage_'.$groupChatID, $start, $stop);193         if($json_message)194             return $json_message;195         return false;196     }197 198 199     /**200     * @desc 加锁方法201     *202     * @param $lockName string | 锁的名字203     * @param $timeout int | 锁的过期时间204     *205     * @return 成功返回identifier/失败返回false206     */207     public function getLock($lockName, $timeout=2)208     {209         $identifier=uniqid();       #获取唯一标识符210         $timeout=ceil($timeout);    #确保是整数211         $end=time()+$timeout;212         while(time()<$end)          #循环获取锁213         {214             /*215             #这里的set操作可以等同于下面那个if操作,并且可以减少一次与redis通讯216             if($this->redis->set($lockName, $identifier array('nx', 'ex'=>$timeout)))217                 return $identifier;218             */219             if($this->redis->setnx($lockName, $identifier))    #查看$lockName是否被上锁220             {221                 $this->redis->expire($lockName, $timeout);     #为$lockName设置过期时间222                 return $identifier;                             #返回一维标识符223             }224             elseif ($this->redis->ttl($lockName)===-1) 225             {226                 $this->redis->expire($lockName, $timeout);     #检测是否有设置过期时间,没有则加上227             }228             usleep;         #停止0.001ms229         }230         return false;231     }232 233     /**234     * @desc 释放锁235     *236     * @param $lockName string   | 锁名237     * @param $identifier string | 锁的唯一值238     *239     * @param bool240     */241     public function releaseLock($lockName,$identifier)242     {243         if($this->redis->get($lockName)==$identifier)   #判断是锁有没有被其他客户端修改244         { 245             $this->redis->multi();246             $this->redis->del($lockName);   #释放锁247             $this->redis->exec();248             return true;249         }250         else251         {252             return false;   #其他客户端修改了锁,不能删除别人的锁253         }254     }255 256 257 }258 259 ?>

View Code

测试:

  1、建立createGroupChat.php

  试行代码并创制568、569群组

4858.com 49

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #创建群组4 $user='jack';5 $arr=array('jane1','jane2');6 $a=$object->createGroupChat($user,$arr);7 echo "<pre>";8 print_r($a);9 echo "</pre>";die;

4858.com 50

4858.com 51

4858.com 52

  2、建立addMembers.php

  实施代码并加多新成员

4858.com 53

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 $b=$object->addMembers('jack','568',array('jane1','jane2','jane3','jane4'));4 echo "<pre>";5 print_r($b);6 echo "</pre>";die;

4858.com 54

4858.com 55

  3、创设delete.php(测量检验群主删除成员功效)

4858.com 56

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #群主删除成员4 $c=$object->delMembers('jack', '568', array('jane1','jane4'));5 echo "<pre>";6 print_r($c);7 echo "</pre>";die;

4858.com 57

4858.com 58

  4、建立sendMessage.php

  多实行一次,568、569都发几条

4858.com 59

 1 include './ManyPullMessage.class.php'; 2 $object=new ManyPullMessage('192.168.95.11'); 3 #发送消息 4 $user='jane2'; 5 $message='go go go'; 6 $groupChatID=568; 7 $arr=array('sender'=>$user, 'message'=>$message, 'time'=>time; 8 $d=$object->sendMessage($user,$groupChatID,$arr); 9 echo "<pre>";10 print_r($d);11 echo "</pre>";die;

4858.com 60

4858.com 61

4858.com 62

  5、创建getNewMessage.php(测验用户获得新音信功能)

4858.com 63

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #用户获取新消息4 $e=$object->getNewMessage('jane2');5 echo "<pre>";6 print_r($e);7 echo "</pre>";die;

4858.com 64

4858.com 65

  6、创立getPartMessage.php(测验用户得到某些群组部分音讯)

  (多发送几条消息,用于测量检验。56第88中学国共产党18条数据)

4858.com 66

1 include './ManyPullMessage.class.php';2 $object=new ManyPullMessage('192.168.95.11');3 #用户获取某个群组部分消息4 $f=$object->getPartMessage('jane2', 568, 1, 10); 5 echo "<pre>";6 print_r($f);7 echo "</pre>";die;

4858.com 67

page=1,size=10

4858.com 68

page=2,size=10

4858.com 69

测量检验甘休,还亟需其余成效能够友善开始展览改变增多测量试验。

这一次整治那篇小说绝相比较较赶,心里早就想着快点整理完赶紧学习别的的手艺啦,哈哈22333。各位大神请留步,恳请各位给点学习redis的指导意见,本人工作偏向是PHP

(以上是自身的一对观念,若有欠缺恐怕失实的地方请各位提出)

装载:

声称:本博客小说为原创,只象征本人在办事学习中某一时间内总括的见解或结论。转发时请在篇章页面显著地点给出原版的书文链接

2、落成情势

音信传递即七个只怕多少个客户端在相互发送和收受音信。

日常有三种方法完结:

首先种为消息推送。Redis内置有这种体制,publish往频道推送音信、subscribe订阅频道。这种格局有贰个短处正是必须确定保证接收者时刻在线(正是此时程序不能够停下来,向来维持监控状态,借使断线后就能油然则生客户端错失音讯)

第三种为新闻拉取。所谓音讯拉取,正是客户端自己作主去获取存款和储蓄在服务器中的数据。Redis内部未有完毕新闻拉取这种体制。因而我们须求自身手动编写代码去完成这一个职能。

在此处大家,大家越来越将音讯传递再细分为一对一的消息传递,多对多的音讯传递(群组音讯传递)。

【注:三个类的代码相对很多,由此将其折叠起来了】

3、一对一音讯传递

事例1:一对一音信发送与收获

模块必要:

1、提醒有个别许个挂钩人发来新新闻

2、音讯包罗发赠与外人、时间、消息内容

3、能够拿走此前的旧音讯

4858.com ,4、而且音讯能够保持7天,过期将会被动触发删除

Redis完结思路:

1、新消息与旧新闻分别选用多少个链表来存款和储蓄

2、原始新闻的布局选择数组的样式寄放,並且满含发送给外人、时间戳、音讯内容

3、在推入redis的链表前,供给将数据转变为json类型然后再进行仓库储存

4、在抽取新音讯时应有运用rpoplpush来达成,将已读的新音讯推入旧音信链表中

5、抽出旧音信时,应该用旧信息的年月与当今的岁月进行相比,若超时,则直接删除后边的全部数码(因为数量是定期间多少个三个压进链表中的,所以对于时间是一步一趋排列的)

数码存储结构图:

4858.com 70

PHP的兑当代码:

#SinglePullMessage.class.php

<?php
#单接接收者接收消息
class SinglePullMessage
{
 private $redis=''; #存储redis对象
 /**
 * @desc 构造函数
 * 
 * @param $host string | redis主机
 * @param $port int | 端口
 */
 public function __construct($host,$port=6379)
 {
 $this->redis=new Redis();
 $this->redis->connect($host,$port);
 } 
 /**
 * @desc 发送消息(一个人)
 * 
 * @param $toUser string | 接收人
 * @param $messageArr array | 发送的消息数组,包含sender、message、time 
 *
 * @return bool
 */
 public function sendSingle($toUser,$messageArr)
 {
 $json_message=json_encode($messageArr); #编码成json数据
 return $this->redis->lpush($toUser,$json_message); #将数据推入链表 
 }
 /**
 * @desc 用户获取新消息
 *
 * @param $user string | 用户名
 *
 * @return array 返回数组,包含多少个用户发来新消息,以及具体消息
 */
 public function getNewMessage($user)
 {
 #接收新信息数据,并且将数据推入旧信息数据链表中,并且在原链表中删除
 $messageArr=array();
 while($json_message=$this->redis->rpoplpush($user, 'preMessage_'.$user))
 {
  $temp=json_decode($json_message); #将json数据变成对象
  $messageArr[$temp->sender][]=$temp; #转换成数组信息
 }
 if($messageArr)
 {
  $arr['count']=count($messageArr); #统计有多少个用户发来信息
  $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; #数据过期时间 七天过期
  if($timeout<time())  #判断数据是否过期
  {
  if($k==0)   #若是最迟插入的数据都过期了,则将所有数据删除
  {
   $this->redis->del('preMessage_'.$user);
   break;
  }
  $this->redis->ltrim('preMessage_'.$user, 0, $k); #若检测出有过期的,则将比它之前插入的所有数据删除
  break;
  }
  $messageArr[$temp->sender][]=$temp;
 }
 return $messageArr;
 }
 /**
 * @desc 消息处理,没什么特别的作用。在这里这是用来处理数组信息,然后将其输出。 
 *
 * @param $arr array | 需要处理的信息数组
 *
 * @return 返回打印输出
 */
 public function dealArr($arr)
 {
 foreach ($arr as $k => $v) 
 {
  foreach ($v as $k1 => $v2) 
  {
  echo '发送人:'.$v2->sender.' 发送时间:'.date('Y-m-d h:i:s',$v2->time).'<br/>';
  echo '消息内容:'.$v2->message.'<br/>';
  }
  echo "<hr/>";
 }
 }
}

测试:

1、发送音讯

#建立test1.php

include './SinglePullMessage.class.php';
$object=new SinglePullMessage('192.168.95.11');
#发送消息
$sender='boss'; #发送者
$to='jane';  #接收者
$message='How are you'; #信息
$time=time();
$arr=array('sender'=>$sender,'message'=>$message,'time'=>$time);
echo $object->sendSingle($to,$arr);

2、获取新消息

#建立test2.php

include './SinglePullMessage.class.php';
$object=new SinglePullMessage('192.168.95.11');
#获取新消息
$arr=$object->getNewMessage('jane');
if($arr)
{
 echo $arr['count']."个联系人发来新消息<br/><hr/>";
 $object->dealArr($arr['messageArr']); 
}
else
 echo "无新消息";

访问结果:

4858.com 71

3、获取旧新闻

#建立test3.php

include './SinglePullMessage.class.php';
$object=new SinglePullMessage('192.168.95.11');
#获取旧消息
$arr=$object->getPreMessage('jane');
if($arr)
{
 $object->dealArr($arr);
}
else
 echo "无旧数据";

4、多对多音讯传递

事例2:多对多信息发送与收获(就是群组)

模块需求:

1、用户能够活动创造群组,并化作群主

2、群主能够推人进来作为群组成员、何况可以踢人

3、用户能够直接退出群组

4、可以发送消息,每一人成员都足以拉取音信

5、群组的新闻最大容纳量为四千条

6、成员能够拉取新消息,并提醒有稍许新音信

7、成员能够分页获取在此之前已读的旧音信

。。。。。作用就写那多少个呢,有亟待可能想演练的同桌们得以扩大其余职能,举例禁言、佚名新闻发送、文件发送等等。

Redis达成思路:

1、群组的信息以及群组的积极分子组成选择有序聚焦进行仓储。群组音信有序聚焦的member存款和储蓄用户发送的json数据音信,score存款和储蓄独一值,将选拔原子操作incr获取string中的自增加值进行仓储;群组成员有序聚焦的member存款和储蓄user,score存款和储蓄非零数字(在此地那些score意义比相当的小,作者的例子代码中接纳数字1为群主的score,其余的蕴藏为2。当然那使用这些数额仍能扩展别的功效,比方群组中成员品级)可参照上面数据存款和储蓄结构简图。

2、用户所步入的群组也是行使有序聚焦实行仓库储存。个中,member存储群组ID,score存款和储蓄用户已经获得该群组的最大消息分值(对应群组音讯的score值)

3、用户成立群组的时候,通过原子操作incr进而获取一个独一ID

4、用户在群中发送新闻时,也是由此原子操作incr获取二个独一自增加平稳ID

5、在实行incr时,为严防出现导致竞争关系,由此需求张开加锁操作【redis详细锁的助教能够参照:Redis营造布满式锁//www.jb51.net/article/109704.htm】

6、创设群组方法简单思路,任何贰个用户都得以创立群组聊天,在创立的还要,能够选择时是或不是丰裕群组成员(参数通过数组的样式)。创设进度将会为那些群营造设构造三个群组成员有序集中(群组音信有序聚焦目前不创设),接着将群主增加进去,再将群ID加多用户所参预的群组有序聚聚焦。

数码存款和储蓄结构图:

4858.com 72

4858.com 73

PHP的代码完结:

#ManyPullMessage.class.php

<?php
class ManyPullMessage
{
 private $redis=''; #存储redis对象
 /**
 * @desc 构造函数
 * 
 * @param $host string | redis主机
 * @param $port int | 端口
 */
 public function __construct($host,$port=6379)
 {
 $this->redis=new Redis();
 $this->redis->connect($host,$port);
 } 
 /**
 * @desc 用于创建群组的方法,在创建的同时还可以拉人进群组
 * 
 * @param $user string | 用户名,创建群组的主人
 * @param $addUser array | 其他用户构成的数组
 *
 * @param $lockName string | 锁的名字,用于获取群组ID的时候用
 * @return int 返回群组ID
 */
 public function createGroupChat($user, $addUser=array(), $lockName='chatIdLock')
 {
 $identifier=$this->getLock($lockName); #获取锁
 if($identifier)
 {
  $id=$this->redis->incr('groupChatID'); #获取群组ID
  $this->releaseLock($lockName,$identifier); #释放锁
 }
 else
  return false;
 $messageCount=$this->redis->set('countMessage_'.$id, 0); #初始化这个群组消息计数器
 #开启非事务型流水线,一次性将所有redis命令传给redis,减少与redis的连接
 $pipe=$this->redis->pipeline(); 
 $this->redis->zadd('groupChat_'.$id, 1, $user); #创建群组成员有序集合,并添加群主
 #将这个群组添加到user所参加的群组有序集合中
 $this->redis->zadd('hasGroupChat_'.$user, 0, $id); 
 foreach ($addUser as $v) #创建群组的同时需要添加的用户成员
 {
  $this->redis->zadd('groupChat_'.$id, 2, $v);
  $this->redis->zadd('hasGroupChat_'.$v, 0, $id);
 }
 $pipe->exec();
 return $id; #返回群组ID
 }
 /**
 * @desc 群主主动拉人进群
 *
 * @param $user string | 群主名
 * @param $groupChatID int | 群组ID
 * @param $addMembers array | 需要拉进群的用户
 *
 * @return bool
 */
 public function addMembers($user, $groupChatID, $addMembers=array())
 {
 $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user); #将groupChatName的群主取出来
 if($groupMasterScore==1) #判断user是否是群主
 {
  $pipe=$this->redis->pipeline(); #开启非事务流水线
  foreach ($addMembers as $v) 
  {
  $this->redis->zadd('groupChat_'.$groupChatID, 2, $v);   #添加进群
  $this->redis->zadd('hasGroupChat_'.$v, 0, $groupChatID); #添加群名到用户的有序集合中
  }
  $pipe->exec();
  return true;
 }
 return false;
 }
 /**
 * @desc 群主删除成员
 *
 * @param $user string | 群主名
 * @param $groupChatID int | 群组ID
 * @param $delMembers array | 需要删除的成员名字
 *
 * @return bool
 */
 public function delMembers($user, $groupChatID, $delMembers=array())
 {
 $groupMasterScore=$this->redis->zscore('groupChat_'.$groupChatID, $user); 
 if($groupMasterScore==1) #判断user是否是群主
 {
  $pipe=$this->redis->pipeline(); #开启非事务流水线
  foreach ($delMembers as $v) 
  {
  $this->redis->zrem('groupChat_'.$groupChatID, $v);   
  $this->redis->zrem('hasGroupChat_'.$v, $groupChatID); 
  }
  $pipe->exec();
  return true;
 }
 return false;
 }
 /**
 * @desc 退出群组
 *
 * @param $user string | 用户名
 * @param $groupChatID int | 群组名
 */
 public function quitGroupChat($user, $groupChatID)
 {
 $this->redis->zrem('groupChat_'.$groupChatID, $user);
 $this->redis->zrem('hasGroupChat_'.$user, $groupChatID);
 return true;
 }
 /**
 * @desc 发送消息
 *
 * @param $user string | 用户名
 * @param $groupChatID int | 群组ID
 * @param $messageArr array | 包含发送消息的数组
 * @param $preLockName string | 群消息锁前缀,群消息锁全名为countLock_群ID
 *
 * @return bool
 */
 public function sendMessage($user, $groupChatID, $messageArr, $preLockName='countLock_')
 {
 $memberScore=$this->redis->zscore('groupChat_'.$groupChatID, $user); #成员score
 if($memberScore)
 {
  $identifier=$this->getLock($preLockName.$groupChatID); #获取锁
  if($identifier) #判断获取锁是否成功
  {
  $messageCount=$this->redis->incr('countMessage_'.$groupChatID);
  $this->releaseLock($preLockName.$groupChatID,$identifier); #释放锁
  }
  else
  return false;
  $json_message=json_encode($messageArr);
  $this->redis->zadd('groupChatMessage_'.$groupChatID, $messageCount, $json_message);
  $count=$this->redis->zcard('groupChatMessage_'.$groupChatID); #查看信息量大小
  if($count>5000) #判断数据量有没有达到5000条
  { #数据量超5000,则需要清除旧数据
  $start=5000-$count;
  $this->redis->zremrangebyrank('groupChatMessage_'.$groupChatID, $start, $count);
  }
  return true;
 }
 return false;
 }
 /**
 * @desc 获取新信息
 *
 * @param $user string | 用户名
 *
 * @return 成功则放回json数据数组,无新信息返回false
 */
 public function getNewMessage($user)
 {
 $arrID=$this->redis->zrange('hasGroupChat_'.$user, 0, -1, 'withscores'); #获取用户拥有的群组ID
 $json_message=array(); #初始化
 foreach ($arrID as $k => $v) #遍历循环所有群组,查看是否有新消息
 {
  $messageCount=$this->redis->get('countMessage_'.$k); #群组最大信息分值数
  if($messageCount>$v) #判断用户是否存在未读新消息
  {
  $json_message[$k]['message']=$this->redis->zrangebyscore('groupChatMessage_'.$k, $v+1, $messageCount);
  $json_message[$k]['count']=count($json_message[$k]['message']); #统计新消息数量
  $this->redis->zadd('hasGroupChat_'.$user, $messageCount, $k); #更新已获取消息
  } 
 }
 if($json_message)
  return $json_message;
 return false;
 }
 /**
 * @desc 分页获取群组信息
 *
 * @param $user string | 用户名 
 * @param $groupChatID int | 群组ID
 * @param $page int | 第几页
 * @param $size int | 每页多少条数据
 *
 * @return 成功返回json数据,失败返回false
 */
 public function getPartMessage($user, $groupChatID, $page=1, $size=10)
 {
 $start=$page*$size-$size; #开始截取数据位置
 $stop=$page*$size-1; #结束截取数据位置
 $json_message=$this->redis->zrevrange('groupChatMessage_'.$groupChatID, $start, $stop);
 if($json_message)
  return $json_message;
 return false;
 }
 /**
 * @desc 加锁方法
 *
 * @param $lockName string | 锁的名字
 * @param $timeout int | 锁的过期时间
 *
 * @return 成功返回identifier/失败返回false
 */
 public function getLock($lockName, $timeout=2)
 {
 $identifier=uniqid(); #获取唯一标识符
 $timeout=ceil($timeout); #确保是整数
 $end=time()+$timeout;
 while(time()<$end)  #循环获取锁
 {
  /*
  #这里的set操作可以等同于下面那个if操作,并且可以减少一次与redis通讯
  if($this->redis->set($lockName, $identifier array('nx', 'ex'=>$timeout)))
  return $identifier;
  */
  if($this->redis->setnx($lockName, $identifier)) #查看$lockName是否被上锁
  {
  $this->redis->expire($lockName, $timeout); #为$lockName设置过期时间
  return $identifier;    #返回一维标识符
  }
  elseif ($this->redis->ttl($lockName)===-1) 
  {
  $this->redis->expire($lockName, $timeout); #检测是否有设置过期时间,没有则加上
  }
  usleep(0.001);  #停止0.001ms
 }
 return false;
 }
 /**
 * @desc 释放锁
 *
 * @param $lockName string | 锁名
 * @param $identifier string | 锁的唯一值
 *
 * @param bool
 */
 public function releaseLock($lockName,$identifier)
 {
 if($this->redis->get($lockName)==$identifier) #判断是锁有没有被其他客户端修改
 { 
  $this->redis->multi();
  $this->redis->del($lockName); #释放锁
  $this->redis->exec();
  return true;
 }
 else
 {
  return false; #其他客户端修改了锁,不能删除别人的锁
 }
 }

}
?>

测试:

1、建设构造createGroupChat.php(测验创制群组效用)

实践代码并创造568、569群组(群主为jack)

include './ManyPullMessage.class.php';
$object=new ManyPullMessage('192.168.95.11');
#创建群组
$user='jack';
$arr=array('jane1','jane2');
$a=$object->createGroupChat($user,$arr);
echo "<pre>";
print_r($a);
echo "</pre>";die;

4858.com 74

4858.com 75

2、建设构造addMembers.php(测量检验增添成员作用)

推行代码并增多新成员

 include './ManyPullMessage.class.php';
 $object=new ManyPullMessage('192.168.95.11');
 $b=$object->addMembers('jack','568',array('jane1','jane2','jane3','jane4'));
 echo "<pre>";
 print_r($b);
 echo "</pre>";die;

4858.com 76

3、创建delete.php(测量检验群主删除成员功用)

include './ManyPullMessage.class.php';
$object=new ManyPullMessage('192.168.95.11');
#群主删除成员
$c=$object->delMembers('jack', '568', array('jane1','jane4'));
echo "<pre>";
print_r($c);
echo "</pre>";die;

4858.com 77

4、创立sendMessage.php(测量检验发送消息成效)

多实施四回,568、569都发几条

include './ManyPullMessage.class.php';
$object=new ManyPullMessage('192.168.95.11');
#发送消息
$user='jane2';
$message='go go go';
$groupChatID=568;
$arr=array('sender'=>$user, 'message'=>$message, 'time'=>time());
$d=$object->sendMessage($user,$groupChatID,$arr);
echo "<pre>";
print_r($d);
echo "</pre>";die;

4858.com 78

4858.com 79

5、创立getNewMessage.php(测量试验用户获得新新闻成效)

include './ManyPullMessage.class.php';
$object=new ManyPullMessage('192.168.95.11');
#用户获取新消息
$e=$object->getNewMessage('jane2');
echo "<pre>";
print_r($e);
echo "</pre>";die;

4858.com 80

6、创立getPartMessage.php(测量检验用户获得某些群组部分音信)

(多发送几条音讯,用于测量试验。568国共18条数据)

include './ManyPullMessage.class.php';
$object=new ManyPullMessage('192.168.95.11');
#用户获取某个群组部分消息
$f=$object->getPartMessage('jane2', 568, 1, 10); 
echo "<pre>";
print_r($f);
echo "</pre>";die;

page=1,size=10

4858.com 81

page=2,size=10

4858.com 82

测量检验结束,还必要别的功用能够友善实行修改增多测量试验。

此次整治那篇小说相对相比较赶,心里早就想着快点整理完赶紧学习别的的本领啦,哈哈。各位大神请留步,恳请各位给点学习redis的引导意见,本身专门的学问偏侧是PHP

如上正是本文的全体内容,希望本文的内容对我们的学习或许工作能拉动一定的扶持,同期也指望多多扶助脚本之家!

你或然感兴趣的篇章:

  • PHP使用Redis达成防止大并发下二遍写入的秘籍
  • 详解thinkphp+redis+队列的兑当代码
  • php完结的redis缓存类定义与应用方法亲自过问
  • PHP完毕电商订单自动确认收货redis队列
  • PHP基于Redis音讯队列完结公布今日头条的措施
  • 跌落PHP Redis内部存款和储蓄器占用
  • php+redis完结登记、删除、编辑、分页、登入、关心等效果示例
  • ubuntu 系统上为php加上redis
    扩张的完结方式

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有