Mina, Netty, twisted study Together (VI): Session

Source: Internet
Author: User
Tags throwable

Students who have developed Web applications should always use the session. Because the HTTP protocol itself is stateless, a client accesses multiple pages of the Web application multiple times, and the server cannot tell if the client is the same client with multiple accesses. With the session, you can set some client-related properties to maintain this connection state. For example, when the user logs on to the system and the session flag is set, the client is logged on, so you don't have to log in again when you visit another page.

However, the content of this article is not the session of the Web application, but the session of the TCP connection, in fact, there are very big differences. The session implementation of the Web application is not based on the same TCP connection, but is implemented through a cookie, which is no longer detailed. The previous session of the Web application is just to let you understand the concept of the session.

In synchronous blocking network programming, code is written in the order of TCP operations, which is to create a connection, read and write multiple times, close the connection, so it is easy to determine whether the sequence of operations is the same connection. In an event-driven asynchronous network programming framework, an IO operation triggers an event to invoke the corresponding event function, such as new data received from the client, called messagereceived (MINA), Channelread (Netty), DataReceived (Twisted), multiple requests for the same TCP connection and multiple client requests are the same.

So how to tell if multiple requests are not the same TCP connection, how to save connection related information? For this problem, MINA, Netty, twisted all provide the corresponding solution.

The following respectively implements a request count counter with Mina, Netty, and twisted to record the number of requests for the same connection multiple times.

MINA:

In Mina, whenever a client connects to the server, a new iosession is created until the client disconnects. Iosession can use setattribute and getattribute to store and retrieve information about a TCP connection.

 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 (); }    //Receive new Data@Override Public voidMessagereceived (iosession session, Object message)throwsException {intCounter = 1; //first request, create a counter in session        if(Session.getattribute ("counter") = =NULL) {Session.setattribute ("Counter", 1); } Else {            //get counter in session, add 1 and then save to sessionCounter = (Integer) session.getattribute ("Counter"); Counter++; Session.setattribute ("Counter", counter); } String Line=(String) message; System.out.println ("First" + Counter + "Request:" +Line ); }}

Netty:

There are two cases in Netty, one is to create a new Channelhandler instance for each TCP connection, and the other is to share a Channelhandler instance for all TCP connections. The difference between the two approaches is whether the new Channelhandler instance is added to the Channelpipeline AddLast method.

Create a new Channelhandler instance for each TCP connection:

Creating a new Channelhandler instance for each TCP connection is one of the most common ways. This is a very simple situation where you can save connection-related information by adding a member variable directly to the Channelhandler implementation class.

 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 (NewTcpserverhandler ());//Create a new Channelhandler instance for each TCP connection                        }                    }); Channelfuture F= B.bind (8080). sync ();        F.channel (). Closefuture (). sync (); } finally{workergroup.shutdowngracefully ();        Bossgroup.shutdowngracefully (); }    }}classTcpserverhandlerextendsChannelinboundhandleradapter {//connection related information is stored directly in the member variable of the Tcpserverhandler    Private intCounter = 0; @Override Public voidChannelread (Channelhandlercontext ctx, Object msg) {counter++; String Line=(String) msg; System.out.println ("First" + Counter + "Request:" +Line ); } @Override Public voidexceptioncaught (Channelhandlercontext ctx, throwable cause) {cause.printstacktrace ();    Ctx.close (); }}

All TCP connections share a single Channelhandler instance:

In this case, the connection-related information cannot be placed in the member variables of the Channelhandler implementation class, otherwise the information will be shared by other connections. This is where the Channelhandlercontext attribute is going to be used.

 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>() {                                                PrivateTcpserverhandler Tcpserverhandler =NewTcpserverhandler (); @Override Public voidInitchannel (Socketchannel ch)throwsException {Channelpipeline pipeline=Ch.pipeline (); Pipeline.addlast (NewLinebasedframedecoder (80)); Pipeline.addlast (NewStringdecoder (charsetutil.utf_8)); Pipeline.addlast (Tcpserverhandler); //multiple connections using the same Channelhandler instance                        }                    }); Channelfuture F= B.bind (8080). sync ();        F.channel (). Closefuture (). sync (); } finally{workergroup.shutdowngracefully ();        Bossgroup.shutdowngracefully (); } }} @Sharable//Multiple connections use the same channelhandler, add @sharable annotationsclassTcpserverhandlerextendsChannelinboundhandleradapter {Privateattributekey<integer> Attributekey = attributekey.valueof ("Counter"); @Override Public voidChannelread (Channelhandlercontext ctx, Object msg) {Attribute<Integer> attribute =ctx.attr (Attributekey); intCounter = 1; if(Attribute.get () = =NULL) {Attribute.set (1); } Else{counter=Attribute.get (); Counter++;        Attribute.set (counter); } String Line=(String) msg; System.out.println ("First" + Counter + "Request:" +Line ); } @Override Public voidexceptioncaught (Channelhandlercontext ctx, throwable cause) {cause.printstacktrace ();    Ctx.close (); }}

Twisted:

In twisted, each TCP connection creates a new protocol instance, which is simple enough to save the connection-related information directly as a property of the Protocol inheriting class.

#-*-coding:utf-8–*- fromTwisted.protocols.basicImportLineonlyreceiver fromTwisted.internet.protocolImportFactory fromTwisted.internetImportreactorclassTcpserverhandle (lineonlyreceiver):deflinereceived (self, data):if(Hasattr (Self,'counter')): Self.counter+ = 1Else: Self.counter= 1; Print "Section"+ STR (self.counter) +"Second Request:"+DataFactory=Factory () Factory.protocol=Tcpserverhandlereactor.listentcp (8080, Factory) Reactor.run ()

The following is a Java-implemented client that has 3 TCP connections in the code and two request data to the server in each connection:

 Public classTcpClient { Public Static voidMain (string[] args)throwsIOException, interruptedexception {//3 TCP connections, sending 2 request data per connection         for(inti = 0; I < 3; i++) {Socket Socket=NULL; OutputStream out=NULL; Try{Socket=NewSocket ("localhost", 8080); out=Socket.getoutputstream (); //first-time request serverString lines1 = "hello\r\n"; byte[] outputBytes1 = Lines1.getbytes ("UTF-8");                Out.write (OUTPUTBYTES1);                    Out.flush (); //Second Request ServerString lines2 = "world\r\n"; byte[] OutputBytes2 = Lines2.getbytes ("UTF-8");                Out.write (OutputBytes2);                Out.flush (); } finally {                //Close ConnectionOut.close ();            Socket.close (); } thread.sleep (1000); }    }}

Test the above 4 servers separately, the output is:

1th Time Request: Hello
2nd Request: World
1th Time Request: Hello
2nd Request: World
1th Time Request: Hello
2nd Request: World

Mina, Netty, twisted study Together (VI): Session

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.