Mina, Netty, twisted Together (vii): Publish/Subscribe (publish/subscribe)

Source: Internet
Author: User
Tags throwable

There are many ways to message delivery, and request/response (request/reply) is the most common. In the example in the previous blog post, many are in Request/response mode, and when the server receives the message, it immediately writes back a message to the client. The HTTP protocol is also based on the request/response approach.

However, the request/response does not meet all the messaging requirements, and some requirements may require the server to proactively push the message to the client instead of passively waiting for the request to respond.

Publish/Subscribe (Publish/subscribe) is a way for a server to send messages to the client proactively. After the Subscriber Subscriber connects to the server client, it is equivalent to starting a subscription to Publisher Publisher's message, and when the publisher publishes a message, all subscribers receive the message.

Web chat rooms are typically implemented based on a publish/subscribe model. For example, join a QQ group, it is equivalent to subscribe to all the messages of this group, when there are new messages, the server will actively send messages to all clients. But everyone in the chat room is both a publisher and a subscriber.

The following respectively, with Mina, Netty, twisted to implement a simple publish/subscribe mode of the server program, all the clients connected to the server are subscribers, when the publisher publishes a message, the server forwards the message to all clients.

MINA:

In Mina, the Ioservice getmanagedsessions () method can be used to obtain all iosession currently managed by this ioservice, that is, all the client collections connected to the server. When the server receives a message published by the publisher, the Ioservice getmanagedsessions () method can be used to obtain iosession for all clients and send messages to those clients.

 Public classTCPServer { Public Static voidMain (string[] args)throwsIOException {ioacceptor acceptor=NewNiosocketacceptor (); Acceptor.getfilterchain (). AddLast ("Codec",                NewProtocolcodecfilter (NewTextlinecodecfactory (Charset.forname ("UTF-8"), "\ r \ n", "\ r \ n"))); Acceptor.sethandler (NewTcpserverhandle ()); Acceptor.bind (NewInetsocketaddress (8080)); }}classTcpserverhandleextendsIohandleradapter {@Override Public voidExceptioncaught (iosession session, Throwable Cause)throwsException {cause.printstacktrace (); } @Override Public voidMessagereceived (iosession session, Object message)throwsException {//get all the iosession that are being connectedcollection<iosession> sessions =Session.getservice (). Getmanagedsessions (). values (); //write the message to all Iosessionioutil.broadcast (message, sessions); }}

Netty:

Netty provides channelgroup for saving the channel group, Channelgroup is a thread-safe collection of channel, which provides some column channel bulk operations. When a TCP connection is closed, the corresponding channel is automatically removed from the Channelgroup, so no manual removal of the closed channel is necessary.

Netty documentation on Channelgroup explanation:

A Thread-safe Set, contains open Channels and provides various bulk operations on them. Using Channelgroup, you can categorize Channels to a meaningful group (e.g. on a per-service or per-state basis.) A closed Channel is automatically removed from the collection and so then you don ' t need to worry about the life cycle of the Added Channel. A Channel can belong to more than one channelgroup.

When a new client connects to the server, the corresponding channel is added to a channelgroup, and when the publisher publishes the message, the server can write the message through Channelgroup to all clients.

 Public classTCPServer { Public Static voidMain (string[] args)throwsinterruptedexception {eventloopgroup bossgroup=NewNioeventloopgroup (); Eventloopgroup Workergroup=NewNioeventloopgroup (); Try{Serverbootstrap b=NewServerbootstrap (); B.group (Bossgroup, Workergroup). Channel (Nioserversocketchannel.class). Childhandler (NewChannelinitializer<socketchannel>() {@Override Public voidInitchannel (Socketchannel ch)throwsException {Channelpipeline pipeline=Ch.pipeline (); Pipeline.addlast (NewLinebasedframedecoder (80)); Pipeline.addlast (NewStringdecoder (charsetutil.utf_8)); Pipeline.addlast (NewStringencoder (charsetutil.utf_8)); Pipeline.addlast (NewTcpserverhandler ());            }                    }); Channelfuture F= B.bind (8080). sync ();        F.channel (). Closefuture (). sync (); } finally{workergroup.shutdowngracefully ();        Bossgroup.shutdowngracefully (); }    }}classTcpserverhandlerextendsChannelinboundhandleradapter {//Channelgroup is used to save all connected clients, note that static is used to ensure that there is only one channelgroup instance, otherwise each new tcpserverhandler will create a channelgroup    Private StaticChannelgroup channels =NewDefaultchannelgroup (globaleventexecutor.instance); @Override Public voidchannelactive (Channelhandlercontext ctx) {Channels.add (Ctx.channel ());//Adding a new connection to the Channelgroup will automatically remove the corresponding channel when the connection is disconnected Channelgroup} @Override Public voidChannelread (Channelhandlercontext ctx, Object msg) {Channels.writeandflush (msg+ "\ r \ n");//after receiving the message, send the message to all clients in the Channelgroup} @Override Public voidexceptioncaught (Channelhandlercontext ctx, throwable cause) {//Cause.printstacktrace (); Temporarily print out the exception, because Publishclient will disconnect immediately after publishing a message, and the server will send a message to publishclient, so an exception will be thrownCtx.close (); }}

Twisted:

In twisted, global data is typically placed in factory, and each connection-related data is placed in protocol. So here you can add a property to the factory to hold the Protocol collection, representing all the clients that connect to the server. When a new client connects to the server, the corresponding protocol instance is placed in the collection, and the corresponding protocol is removed from the collection when the connection is broken. When the server receives a message published by the publisher, it traverses all the clients and sends a message.

#-*-coding:utf-8–*- fromTwisted.protocols.basicImportLineonlyreceiver fromTwisted.internet.protocolImportFactory fromTwisted.internetImportreactorclassTcpserverhandle (lineonlyreceiver):def __init__(self, Factory): Self.factory=FactorydefConnectionmade (self): Self.factory.clients.add (self)#The new connection adds the corresponding protocol instance to the clients    defconnectionlost (self, Reason): Self.factory.clients.remove (self)#connection Disconnects the protocol instance that corresponds to the removal of the connection    deflinereceived (self, line):#Traverse all connections, send data         forCinchSelf.factory.clients:c.sendline (line)classtcpserverfactory (Factory):def __init__(self): self.clients= Set ()#Set collection is used to hold all clients connected to the server    defBuildprotocol (self, addr):returnTcpserverhandle (self) reactor.listentcp (8080, Tcpserverfactory ()) Reactor.run ()

The following are two client programs, one for publishing messages, and one for clients subscribing to messages.

The client that publishes the message is simple-write a message to the server:

 Public classpublishclient { Public Static voidMain (string[] args)throwsIOException {Socket Socket=NULL; OutputStream out=NULL; Try{Socket=NewSocket ("localhost", 8080); out=Socket.getoutputstream (); Out.write ("Hello\r\n". GetBytes ());//Publishing information to the serverOut.flush (); } finally {            //Close ConnectionOut.close ();        Socket.close (); }    }}

When a client that subscribes to a message connects to the server, it blocks the publication message waiting for the receiving server to send:

 Public classsubscribeclient { Public Static voidMain (string[] args)throwsIOException {Socket Socket=NULL; BufferedReader in=NULL; Try{Socket=NewSocket ("localhost", 8080); Inch=NewBufferedReader (NewInputStreamReader (Socket.getinputstream ()));  while(true) {String line= In.readline ();//blocking messages waiting for the server to publishSystem.out.println (line); }        } finally {            //Close ConnectionIn.close ();        Socket.close (); }    }}

Test for Mina, Netty, Twisted servers, respectively:

1, first open the server when testing;
2, and then run the subscription message client subscribeclient,subscribeclient can open more than one;
3. Finally, the client publishclient that runs the release message can run multiple times to see the output of all subscribeclient.

The result can be found that when the client running the publishing message Publishclient publishes a message to the server, the server proactively forwards the message to all TCP connections, and all client subscribeclient that subscribe to the message receive the message and print it out.

Mina, Netty, twisted Together (vii): Publish/Subscribe (publish/subscribe)

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.