Simple subscription publishing mechanism implementation (Golang)

Source: Internet
Author: User
Tags bool redis sprintf

Both Redis and NSQ have well-developed subscription and release implementations, but refer to their source code implementations to make a practical example of the similarities and differences between the two sides and the mechanism will be more impressive.

It is enough to implement a simple subscription/unsubscribe/release information function by eliminating the complexity of the exercise.


Server.go

The dict in the server structure uses a map to store information about the channel, while the channel structure uses a map to hold the client that subscribes to the channel.

This example is not the same as in Redis, where the dict with the channel name as Map Key,value is the corresponding client list. While the client is insured

The channel information for all of its subscriptions is saved.

Package PubSub Import ("Errors" "Sync") type Client struct {Id int Ip string} type Server struct {Dict map[st Ring]*channel//map[channel.name]*channel sync. Rwmutex} func NewServer () *server {s: = &server{} s.dict = Make (Map[string]*channel)//All Channel return S}//Order Read func (SRV *server) Subscribe (client *client, channelname string) {//Customer is SRV in the channel's customer list. Rlock () ch, found: = srv. Dict[channelname] srv. Runlock () if!found {ch = newchannel (channelname) ch. Addclient (client) srv. Lock () srv. Dict[channelname] = ch srv. Unlock ()} else {ch. Addclient (Client)}}//unsubscribe func (SRV *server) unsubscribe (client *client, channelname string) {srv. Rlock () ch, found: = srv. Dict[channelname] srv. Runlock () if found {if ch. Deleteclient (client) = = 0 {ch. Exit () srv. Lock () Delete (srv. Dict, ChannelName) srv. Unlock ()}}}//Publishes message func (SRV *server) publishmessage (channelname, message string) (bool, error) {srv. Rlock () ch, found: = Srv. Dict[channelname] If!found {srv. Runlock () return false, errors.
	New ("ChannelName does not exist!") } srv. Runlock () Ch. Notify (Message) ch. Wait () return True, nil}

Channel.go

Each channel is responsible for putting information into the waitgroup, sending it to the client or queue, in which case a message is printed. When clients is empty, exit ().

Import ("FMT" "Sync" "sync/atomic") type Channel struct {Name string clients map[int]*client//Exitchan C Han int sync. Rwmutex waitgroup waitgroupwrapper messagecount UInt64 exitflag Int32} func Newchannel (ChannelName string) *ch 
	Annel {return &channel{name:channelname,//Exitchan:make (chan int), Clients:make (map[int]*client), }} func (ch *channel) addclient (client *client) bool {ch. Rlock () _, Found: = Ch.clients[client. ID] Ch. Runlock () Ch. Lock () if!found {ch.clients[client. ID] = client} ch. Unlock () return found} func (ch *channel) deleteclient (client *client) int {var ret int ch. Replymsg (FMT. Sprintf ("Remove client:%d from channel:%s", ch. Name, client. Id)) Ch. Lock () Delete (ch.clients, client. ID) Ch. Unlock () Ch. Rlock () ret = len (ch.clients) ch. Runlock () return ret} func (ch *channel) Notify (message string) bool {ch. Rlock () defer ch. Runlock () for CID, _: = Range ch.clients {ch. Replymsg (FMT. Sprintf ("channel:%s client:%d message:%s", ch. Name, CID, message)} return True} func (ch *channel) replymsg (message string) {Ch.waitGroup.Wrap (func () {fmt. PRINTLN (Message)})} func (ch *channel) Wait () {ch.waitGroup.Wait ()} func (ch *channel) Exiting () bool {return ATO Mic. LoadInt32 (&ch.exitflag) = = 1} func (ch *channel) Exit () {if!atomic. CompareAndSwapInt32 (&ch.exitflag, 0, 1) {return}//close (Ch.exitchan) ch. Wait ()} func (ch *channel) putmessage (clientID int, message string) {ch. Rlock () defer ch. Runlock () if Ch. Exiting () {return}//select {//Case <-t.exitchan://Return//} FMT. PRINTLN (Ch. Name, ":", Message) atomic.
 AddUint64 (&ch.messagecount, 1) return}


Main program:

Subscription/release exercise
//author:xiong Chuan Liang  
//date:2015-3-17 package

main

import (
  . "PubSub"
)

func main () {
  C1: = &client{id:100,ip: "172.18.1.1"}
  c3:=  &client{id:300,ip: "172.18.1.3"}

   SRV: = NewServer ()
   srv. Subscribe (C1, "Topic")
   srv. Subscribe (C3, "Topic")

   srv. PublishMessage ("Topic", "Test information 1")

   srv. Unsubscribe (C3, "Topic")
   srv. PublishMessage ("Topic", "Test information 2222")

    srv. Subscribe (C1, "Topic2")
    srv. Subscribe (C3, "Topic2")
    srv. PublishMessage ("Topic2", "Topic2 Test Information")   
}/

*
Run Result:
channel:topic client:100 message: Test information 1
channel:topic client:300 Message: Test information 1
remove client:300
channel:topic client:100 from Channel:topic Message: Test information 2222
channel:topic2 client:100 message:topic2 test information
channel:topic2 client:300 message: Test information for Topic2

*/

Not too complicated to test, a cursory look like no problem.


Mail:xcl_168@aliyun.com

blog:http://blog.csdn.net/xcl168


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.