Redis application in php-sample code sharing for message passing (Figure)

Source: Internet
Author: User
Message passing is widely used in various websites. This function is also essential for a website. This article mainly introduces the application of Redis in php-message transmission. Next, let's take a look at the small series. message passing is widely used in various websites. This function is also essential for a website. This article mainly introduces the application of Redis in php-message transmission. Let's take a look at it with the small editor.

Reading Directory

1. Summary

2. implementation method

3. one-to-one message transmission

4. Multiple-to-multiple message transmission

1. Summary

Message passing is widely used in various websites. This function is also essential for a website. Common messaging applications include @ me in Sina Weibo, comments to you, thumbs up, private messages, and even new things shared on Weibo; zhihu private messages, messages sent from live, and Zhihu team messages.

2. implementation method

Two or more clients send and receive messages to each other.

There are two methods to achieve this:

The first type is message push.Redis has a built-in mechanism in which publish pushes messages to channels and subscribe subscription channels. One disadvantage of this method is that the receiver must be always online (that is, the program cannot be stopped at this time, and the monitoring status is always maintained. if the client loses information after the disconnection)

The second type is message pulling.Message pulling means that the client obtains data stored on the server. Redis does not implement this mechanism internally. Therefore, we need to manually write the code to implement this function.

Here, we further divide the message transmission into one-to-one message transmission and multiple-to-many message transmission (group message transmission ).

[Note: The two classes have a relatively large amount of code, so they are folded up]

3. one-to-one message transmission

Example 1: One-to-one message sending and retrieval

Module requirements:

1. how many contacts have sent new messages?

2. The information includes the sender, time, and content.

3. get old messages

4. the message can be kept for 7 days. expired messages will be deleted passively.

Implementation of Redis:

1. new messages and old messages are stored in two linked lists respectively.

2. the structure of the original message is stored in an array and contains the sender, timestamp, and information.

3. before pushing data to the redis linked list, you need to convert the data to the json type before storing it.

4. use rpoplpush to retrieve new messages and push the read messages to the old linked list.

5. when the old message is retrieved, the time of the old message should be compared with the current time. if it times out, delete all the subsequent data directly (because the data is pressed into the linked list one by time, so the time is ordered)

Data storage structure:

PHP implementation code:

# SinglePullMessage. class. php

 Redis = new Redis (); $ this-> redis-> connect ($ host, $ port);}/*** @ desc send a message (one person) ** @ param $ toUser string | recipient * @ param $ messageArr array | array of sent messages, include sender, message, time ** @ return bool */public function sendSingle ($ toUser, $ messageArr) {$ json_message = json_encode ($ messageArr ); # encode json data return $ this-> redis-> lpush ($ toUser, $ json_message ); # push data to the linked list}/*** @ desc user to get a new message ** @ param $ user string | user name ** @ return array returns an array, how many users send new messages and specific messages */public function getNewMessage ($ user) {# receive new information data and push the data into the old information data link table, and delete $ messageArr = array (); while ($ json_message = $ this-> redis-> rpoplpush ($ user, 'premessage _'. $ user) {$ temp = json_decode ($ json_message); # Convert json data into an object $ messageArr [$ temp-> sender] [] = $ temp; # Convert to Array Information} if ($ messageArr) {$ arr ['count'] = count ($ messageArr ); # count how many users send messages $ arr ['messagearr'] = $ messageArr; return $ arr;} return false;} public function getPreMessage ($ user) {## retrieve old message $ messageArr = array (); $ json_pre = $ this-> redis-> lrange ('premessage _'. $ user, 0,-1); # obtain all old messages in one operation ($ json_pre as $ k => $ v) {$ temp = json_decode ($ v ); # json anti-encoding $ timeout = $ temp-> time + 60*60*24*7; # data expiration time: seven days if ($ timeout
 
  
Redis-> del ('premessage _'. $ user); break;} $ this-> redis-> ltrim ('premessage _'. $ user, 0, $ k); # if any expired data is detected, the break will be deleted from all data inserted before it ;} $ messageArr [$ temp-> sender] [] = $ temp;} return $ messageArr;}/*** @ desc message processing has no special effect. Here this is used to process the Array Information and output it. ** @ Param $ arr array | array of information to be processed ** @ return returns print output */public function dealArr ($ arr) {foreach ($ arr as $ k = >$ v) {foreach ($ v as $ k1 = >$ v2) {echo 'Sender :'. $ v2-> sender. 'sending Time :'. date ('Y-m-d h: I: S', $ v2-> time ).'
  
'; Echo' message content: '. $ v2-> message .'
';} Echo" ";}}}

Test:

1. send messages

# Create test1.php

Include '. /SinglePullMessage. class. php'; $ object = new SinglePullMessage ('2017. 168.95.11 '); # send a message $ sender = 'boss'; # sender $ to = 'jar'; # receiver $ message = 'How are you '; # Information $ time = time (); $ arr = array ('sender' => $ sender, 'message' => $ message, 'Time' => $ time ); echo $ object-> sendSingle ($ to, $ arr );

2. get new messages

# Create test2.php

Include '. /SinglePullMessage. class. php'; $ object = new SinglePullMessage ('2017. 168.95.11 '); # get the new message $ arr = $ object-> getNewMessage ('Jane'); if ($ arr) {echo $ arr ['count']. "contacts send new messages
"; $ Object-> dealArr ($ arr ['messagearr']);} else echo" no new message ";

Access results:

3. get old messages

# Create test3.php

Include '. /SinglePullMessage. class. php'; $ object = new SinglePullMessage ('2017. 168.95.11 '); # get the old message $ arr = $ object-> getPreMessage ('jar'); if ($ arr) {$ object-> dealArr ($ arr );} else echo "no old data ";

4. Multiple-to-multiple message transmission

Example 2: send and retrieve multiple-to-multiple messages (group)

Module requirements:

1. you can create a group and become the group owner.

2. the group owner can pull in as a group member and kicker

3. Users can exit the group directly.

4. messages can be sent. each member can pull messages.

5. The maximum message capacity of a group is 5000.

6. members can pull new messages and prompt how many new messages are there.

7. members can retrieve the previously read old messages by page.

..... You can write these functions. students who need or want to practice can add other functions, such as ban, anonymous message sending, and file sending.

Implementation of Redis:

1. group messages and group members are stored in an ordered set. Member in an ordered set of group messages stores the json data messages sent by users. score stores the unique value. The Atomic operation incr is used to obtain the auto-increment value in the string for storage; the member of the group members in an ordered set stores the user, and the score stores non-zero numbers (here, the score is of little significance. in my example code, the number 1 is the score of the group master, and the other is 2. Of course, this data can be used to expand other functions, such as the membership level in the group.) see the following data storage structure diagram.

2. the group to which a user joins is stored in an ordered set. Among them, the member storage group ID and score storage users have obtained the maximum message score of the group (corresponding to the score value of the group message)

3. when creating a group, you can use the atomic operation incr to obtain a unique ID.

4. when a user sends a message in a group, the user obtains a unique self-increasing ordered ID through the atomic operation incr.

5. during incr execution, to prevent concurrent competition, you need to perform the lock operation. [for details about redis lock, refer to: Redis build distributed lock http://www.jb51.net/article/424704.htm]

6. a brief idea for creating a group. any user can create a group chat. when creating a group chat, you can select whether to add group members (the parameters are in the form of arrays ). The creation process creates an ordered set of group members for this group (the ordered set of group information is not created at the moment), and then adds the group owner, then, add the group ID to the sorted set of groups that the user participates in.

Data storage structure:

PHP code implementation:

# ManyPullMessage. class. php

 Redis = new Redis (); $ this-> redis-> connect ($ host, $ port);}/*** @ desc is used to create a group, you can also pull a person to the group when creating the cluster ** @ param $ user string | user name, create the group owner * @ param $ addUser array | array composed of other users ** @ param $ lockName string | lock name, use * @ return int to return the group ID */public function createGroupChat ($ user, $ addUser = array (), $ lockName = 'chatidlock') when obtaining the group ID ') {$ identifier = $ this-> getLock ($ lockName); # obtain the lock if ($ identifier) {$ id = $ this-> redis -> Incr ('groupchatid'); # obtain the group ID $ this-> releaseLock ($ lockName, $ identifier); # release lock} else return false; $ messageCount = $ this-> redis-> set ('countmessage _'. $ id, 0); # Initialize the message counter of this group # enable the non-transactional pipeline and send all redis commands to redis at one time, reduce connections to redis $ pipe = $ this-> redis-> pipeline (); $ this-> redis-> zadd ('groupchat _'. $ id, 1, $ user); # Create an ordered set of group members, and add the group Owner # add this group to the user's group ordered collection $ this-> redis-> zadd ('hasgroupchat _'. $ user, 0, $ id); foreach ($ DdUser as $ v) # User members to be added when creating a group {$ this-> redis-> zadd ('groupchat _'. $ id, 2, $ v); $ this-> redis-> zadd ('hasgroupchat _'. $ v, 0, $ id) ;}$ pipe-> exec (); return $ id; # return group ID}/*** @ desc the group owner actively pulls people into the group ** @ param $ user string | group main name * @ param $ groupChatID int | group ID * @ param $ addMembers array | user to be pulled into the group ** @ return bool */public function addMembers ($ user, $ groupChatID, $ addMembers = array () {$ groupMasterScore = $ th Is-> redis-> zscore ('groupchat _'. $ groupChatID, $ user); # obtain the groupChatName group owner if ($ groupMasterScore = 1) # determine whether the user is a group master {$ pipe = $ this-> redis-> pipeline (); # enable the non-transaction pipeline foreach ($ addMembers as $ v) {$ this-> redis-> zadd ('groupchat _'. $ groupChatID, 2, $ v); # add to group $ this-> redis-> zadd ('hasgroupchat _'. $ v, 0, $ groupChatID); # Add group names to the user's ordered collection} $ pipe-> exec (); return true;} return false ;} /*** @ desc group owner deletes a member ** @ param $ us Er string | group name * @ param $ groupChatID int | group ID * @ param $ delMembers array | name of the member to be deleted ** @ return bool */public function delMembers ($ user, $ groupChatID, $ delMembers = array () {$ groupMasterScore = $ this-> redis-> zscore ('groupchat _'. $ groupChatID, $ user); if ($ groupMasterScore = 1) # judge whether the user is a group master {$ pipe = $ this-> redis-> pipeline (); # enable non-transaction pipeline foreach ($ delMembers as $ v) {$ this-> redis-> zrem ('groupchat _'. $ gr OupChatID, $ v); $ this-> redis-> zrem ('hasgroupchat _'. $ v, $ groupChatID);} $ pipe-> exec (); return true;} return false ;} /*** @ desc exit Group ** @ param $ user string | user name * @ param $ groupChatID int | group name */public function quitGroupChat ($ user, $ groupChatID) {$ this-> redis-> zrem ('groupchat _'. $ groupChatID, $ user); $ this-> redis-> zrem ('hasgroupchat _'. $ user, $ groupChatID); return true;}/*** @ desc send message ** @ Param $ user string | username * @ param $ groupChatID int | group ID * @ param $ messageArr array | contains the array for sending messages * @ param $ preLockName string | group message lock prefix, group message lock Full name: countLock _ group ID ** @ return bool */public function sendMessage ($ user, $ groupChatID, $ messageArr, $ preLockName = 'countlock _') {$ memberScore = $ this-> redis-> zscore ('groupchat _'. $ groupChatID, $ user); # member score if ($ memberScore) {$ identifier = $ this-> getLock ($ preLock Name. $ groupChatID); # obtain the lock if ($ identifier) # determine whether the lock is successfully obtained {$ messageCount = $ this-> redis-> incr ('countmessage _'. $ groupChatID); $ this-> releaseLock ($ preLockName. $ groupChatID, $ identifier); # release lock} else return false; $ json_message = json_encode ($ messageArr); $ this-> redis-> zadd ('groupchatmessage _'. $ groupChatID, $ messageCount, $ json_message); $ count = $ this-> redis-> zcard ('groupchatmessage _'. $ groupChatID); # view the amount of information if ($ Count> 5000) # determine whether the data volume has reached 5000 records {# if the data volume exceeds 5000, clear the old data $ start = 5000-$ count; $ this-> redis-> zremrangebyrank ('groupchatmessage _'. $ groupChatID, $ start, $ count);} return true;} return false ;} /*** @ desc get new information ** @ param $ user string | username ** @ return returns the json data array, false */public function getNewMessage ($ user) {$ arrID = $ this-> redis-> zrange ('hasgroupchat _'. $ user, 0,-1, 'withscores'); # obtain the group ID owned by the user $ Json_message = array (); # Initialize foreach ($ arrID as $ k => $ v) # traverse all groups in the loop, check whether a new message {$ messageCount = $ this-> redis-> get ('countmessage _'. $ k); # Maximum group information score if ($ messageCount> $ v) # determine whether the user has not read the new message {$ json_message [$ k] ['message'] = $ this-> redis-> zrangebyscore ('groupchatmessage _'. $ k, $ v + 1, $ messageCount); $ json_message [$ k] ['count'] = count ($ json_message [$ k] ['message']); # count the number of new messages $ this-> redis-> zadd ('hasgroupchat _'. $ user, $ m EssageCount, $ k); # Update the acquired message} if ($ json_message) return $ json_message; return false ;} /*** @ desc obtain group information by page ** @ param $ user string | user name * @ param $ groupChatID int | group ID * @ param $ page int | page *@ param $ size int | number of data entries per page ** @ return json data, false */public function getPartMessage ($ user, $ groupChatID, $ page = 1, $ size = 10) {$ start = $ page * $ size-$ size; # Start to intercept the data location $ stop = $ page * $ size-1; # End to intercept the data location $ Json_message = $ this-> redis-> zrevrange ('groupchatmessage _'. $ groupChatID, $ start, $ stop); if ($ json_message) return $ json_message; return false ;} /*** @ desc lock method ** @ param $ lockName string | lock name * @ param $ timeout int | lock expiration time ** @ return success return identifier/failure return false */public function getLock ($ lockName, $ timeout = 2) {$ identifier = uniqid (); # obtain the unique identifier $ timeout = ceil ($ timeout); # make sure it is an integer $ end = time () + $ timeout; While (time () <$ end) # obtain the lock cyclically {/* # The set operation here can be equivalent to the if operation below, in addition, if ($ this-> redis-> set ($ lockName, $ identifier array ('nx ', 'Ex' => $ timeout) can be reduced once for communication with redis ))) return $ identifier; */if ($ this-> redis-> setnx ($ lockName, $ identifier )) # check whether $ lockName is locked {$ this-> redis-> expire ($ lockName, $ timeout); # set the expiration time for $ lockName return $ identifier; # returns a one-dimensional identifier} elseif ($ this-> redis-> ttl ($ lockName) ===- 1) {$ this-> redis-> expire ($ loc KName, $ timeout); # check whether an expiration time is set. If no expiration time is set, add} usleep (0.001); # Stop 0.001 ms} return false ;} /*** @ desc release lock ** @ param $ lockName string | lock name * @ param $ identifier string | unique lock value ** @ param bool */public function releaseLock ($ lockName, $ identifier) {if ($ this-> redis-> get ($ lockName) ==$ identifier) # check whether the lock has been modified by other clients {$ this-> redis-> multi (); $ this-> redis-> del ($ lockName ); # release the lock $ this-> redis-> exec (); return true ;} Else {return false; # Other clients have modified the lock and cannot delete others' locks. }}?>

Test:

1. create createGroupChat. php (test the group creation function)

Run the code and create groups 568 and 569 (the group master is jack)


Include '. /ManyPullMessage. class. php '; $ object = new ManyPullMessage ('2017. 168.95.11 '); # Create a group $ user = 'Jack'; $ arr = array ('jan1', 'jane2'); $ a = $ object-> createGroupChat ($ user, $ arr); echo"
";print_r($a);echo "
"; Die;

2. create addMembers. php (test the member adding function)

Execute code and add new members

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

3. create delete. php (test the group master's function of deleting members)

Include '. /ManyPullMessage. class. php '; $ object = new ManyPullMessage ('2017. 168.95.11 '); # The Group owner deletes the member $ c = $ object-> delMembers ('Jack', '123456', array ('jan1', 'jane4'); echo"
";print_r($c);echo "
"; Die;

4. create sendMessage. php (test the message sending function)

Execute multiple times, send several messages in 568 and 569

Include '. /ManyPullMessage. class. php '; $ object = new ManyPullMessage ('2017. 168.95.11 '); # send a message $ user = 'jane2'; $ message = 'GO go'; $ groupChatID = 568; $ arr = array ('sender' => $ user, 'message' => $ message, 'Time' => time ()); $ d = $ object-> sendMessage ($ user, $ groupChatID, $ arr); echo"
";print_r($d);echo "
"; Die;

5. create getNewMessage. php (test the user's function of getting new messages)

Include '. /ManyPullMessage. class. php '; $ object = new ManyPullMessage ('2017. 168.95.11 '); # The user obtains the new message $ e = $ object-> getNewMessage ('jane2'); echo"
";print_r($e);echo "
"; Die;

6. create getPartMessage. php (test the user's ability to obtain partial messages from a group)

(Send more messages for testing. 568 18 pieces of data)

Include '. /ManyPullMessage. class. php '; $ object = new ManyPullMessage ('2017. 168.95.11 '); # obtain partial messages of a group $ f = $ object-> getPartMessage ('jane2', 568, 1, 10); echo"
";print_r($f);echo "
"; Die;

Page = 1, size = 10

After the test is completed, you also need other functions to modify and add the test on your own.

The above is the details of the Redis application in php-sample code sharing (figure) for message passing. For more information, see other related articles in the first PHP community!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.