Simple subscription publishing mechanism implementation (Golang)

Source: Internet
Author: User
Tags 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.

Practice implementing a simple subscribe/unsubscribe/release information feature is sufficient.


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 is not the same as in Redis, where the dict with the channel name as Map Key,value is its corresponding client list. While the client is insured

With all of its subscribed channel information, there is no such thing as good or bad, and Redis is relatively more convenient for client statistics, which is more concise in practice.

Package Pubsubimport ("Errors" "Sync") type Client struct {Id intip string}type Server struct {Dict Map[string]*channel//ma P[channel.name]*channelsync.rwmutex}func NewServer () *server {s: = &server{}s.dict = Make (Map[string]*Channel)// All Channelreturn s}//subscription func (SRV *server) Subscribe (client *client, channelname string) {//Customer is srv.rlock in the customer list of channel ( ) ch, found: = srv. Dict[channelname]srv. Runlock () if!found {ch = newchannel (channelname) ch. Addclient (client) srv. Lock () srv. Dict[channelname] = chsrv. Unlock ()} else {ch. Addclient (client)}}//unsubscribe from the 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 the 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 stringclients map[int]*client//Exitchan Chan intsync.rwm Utexwaitgroup waitgroupwrappermessagecount uint64exitflag int32}func newchannel (channelName string) *Channel {retur n &channel{name:channelname,//exitchan:make (chan int), Clients:make (map[int]*client),}}func (ch *Channel) Ad Dclient (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 intch. 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 atomic. 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-17package mainimport (  . "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 1channel:topic Client : Message: Test information 1 Delete client:300channel:topic client:100 from Channel:topic message: Test information 2222channel:topic2 client:100 Test information for Message:topic2 channel:topic2 client:300 message:topic2 Test Information */

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


MAIL: [Email protected]

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


Simple subscription publishing mechanism implementation (Golang)

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.