Netty series eight (simple chat room based on WebSocket).

Source: Internet
Author: User
First, preface

Before I wrote a spring integrated WebSocket protocol article--the Spring message WebSocket , So the introduction of the WebSocket protocol is not much to say, You can refer to this article. Here are just a few additional notes. In addition, Netty's support for the WebSocket protocol is much better than Spring and is much more comfortable to use.

WebSocket transmits data in a frame, and each frame represents a part of the message. A complete message may contain many frames.

The WebSocket RFC, published by the IETF, defines 6 frames, and Netty provides a POJO implementation for each of them. The following table lists the frame types and describes their usage.

Second, chat room function description

1. A, B, C and all users can join the same chat room.

2. A sends a message, B, C can be received at the same time, but a does not receive the message sent by itself.

3, when the user has not sent a message for a long time, the system will kick him out of the chat room.

Three, chat room function realization

1. Netty version

<Dependency>     <groupId>Io.netty</groupId>     <Artifactid>Netty-all</Artifactid>     <version>5.0.0.alpha2</version></Dependency>

2, processing HTTP Protocol channelhandler--non-WebSocket protocol request, return to index.html page

 Public classHttprequesthandlerextendsSimplechannelinboundhandler<fullhttprequest> {    Private FinalString Wsuri; Private StaticFile INDEX; Static{URL location= Httprequesthandler.class. Getprotectiondomain (). Getcodesource (). GetLocation (); Try{String path= Location.touri () + "index.html"; Path=!path.contains ("file:")? Path:path.substring (5); INDEX=NewFile (path); } Catch(URISyntaxException e) {e.printstacktrace (); }    }     PublicHttprequesthandler (String wsuri) { This. Wsuri =Wsuri; } @Overrideprotected voidMessagereceived (Channelhandlercontext ctx, fullhttprequest request)throwsException {//if WebSocket is requested, the protocol is upgraded, the reference count is incremented (called Retain ()), and passed to the next Channelhandler//The retain () method needs to be called because, after calling Channelread (), the resource is freed by the release () method and needs to be called retain () to reserve resources        if(Wsuri.equalsignorecase (Request.uri ())) {Ctx.firechannelread (Request.retain ()); } Else {            //processing requests for Continue to comply with the HTTP 1.1 specification            if(httpheaderutil.is100continueexpected (Request)) {send100continue (CTX); }            //Read Index.htmlRandomaccessfile Randomaccessfile =NewRandomaccessfile (INDEX, "R"); HttpResponse Response=NewDefaulthttpresponse (Request.protocolversion (), Httpresponsestatus.ok); Httpheaders Headers=response.headers (); //after the HTTP header information is set, Httprequesthandler will write back a httpresponse to the clientHeaders.set (Httpheadernames.content_type, "text/html; Charset=utf-8 "); BooleanKeepAlive =httpheaderutil.iskeepalive (Request); if(keepAlive) {Headers.setlong (Httpheadernames.content_length, Randomaccessfile.length ());            Headers.set (Httpheadernames.connection, httpheadervalues.keep_alive);            } ctx.write (response); //write index.html to client            if(Ctx.pipeline (). Get (Sslhandler.class) ==NULL) {Ctx.write (NewDefaultfileregion (Randomaccessfile.getchannel (), 0, Randomaccessfile.length ())); } Else{ctx.write (NewChunkedniofile (Randomaccessfile.getchannel ())); }            //writes Lasthttpcontent and flushes to the client, marking the end of the responseChannelfuture channelfuture =Ctx.writeandflush (lasthttpcontent.empty_last_content); if(!keepAlive)            {Channelfuture.addlistener (channelfuturelistener.close); }        }    }    Private voidsend100continue (Channelhandlercontext ctx) {fullhttpresponse response=Newdefaultfullhttpresponse (httpversion.http_1_1, httpresponsestatus.continue);    Ctx.writeandflush (response); } @Override Public voidExceptioncaught (Channelhandlercontext ctx, throwable cause)throwsException {cause.printstacktrace ();    Ctx.close (); }

3, processing the WebSocket protocol channelhandler--processing Textwebsocketframe message Frame

/*** WebSocket Frame: WebSocket transmits data in a frame, each frame represents a part of the message. A complete message may contain many frames*/ Public classTextwebsocketframehandlerextendsSimplechannelinboundhandler<textwebsocketframe> {    Private FinalChannelgroup Group;  PublicTextwebsocketframehandler (channelgroup group) { This. Group =Group; } @Overrideprotected voidMessagereceived (Channelhandlercontext ctx, Textwebsocketframe msg)throwsException {//increase the reference count of the message (keep the message) and write it to all connected clients in the ChannelgroupChannel Channel =Ctx.channel (); //messages sent by themselves are not returned to themselvesGroup.remove (channel);        Group.writeandflush (Msg.retain ());    Group.add (channel); } @Override Public voidUsereventtriggered (Channelhandlercontext ctx, Object evt)throwsException {//If the handshake is successful, upgrade to the Websocket protocol        if(evt = =WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {            //The handshake succeeds, removing the httprequesthandler so that no messages will be received//and add the successful Channel of the handshake to the Channelgroup .Ctx.pipeline (). Remove (Httprequesthandler.class); Group.writeandflush (NewTextwebsocketframe ("Client" + ctx.channel () + "joined"));        Group.add (Ctx.channel ()); } Else if(evtinstanceofidlestateevent) {idlestateevent stateevent=(idlestateevent) evt; if(stateevent.state () = =idlestate.reader_idle)                {Group.remove (Ctx.channel ()); Ctx.writeandflush (NewTextwebsocketframe ("Because you are not online for a long time, the system has kicked you offline!") ") . AddListener (Channelfuturelistener.close); }        } Else {            Super. usereventtriggered (CTX, evt); }    }}

after the WebSocket protocol upgrade is complete, Websocketserverprotocolhandler will replace the Httprequestdecoder with Websocketframedecoder, Httpresponseencoder is replaced with Websocketframeencoder. For maximum performance, it will remove any channelhandler that are not required to be WebSocket connected. This also includes Httpobjectaggregator and Httprequesthandler.

4. chatserverinitializer--multiple Channelhandler merged into Channelpipeline chain

 Public classChatserverinitializerextendsChannelinitializer<channel> {    Private FinalChannelgroup Group; Private Static Final intRead_idle_time_out = 60;//Read Timeout    Private Static Final intwrite_idle_time_out = 0;//Write Timeout    Private Static Final intall_idle_time_out = 0;//All Timeouts     PublicChatserverinitializer (channelgroup group) { This. Group =Group; } @Overrideprotected voidInitchannel (Channel ch)throwsException {Channelpipeline pipeline=Ch.pipeline (); Pipeline.addlast (NewHttpservercodec ()); Pipeline.addlast (NewChunkedwritehandler ()); Pipeline.addlast (NewHttpobjectaggregator (64 * 1024)); //processing requests that are not sent to the/ws URIPipeline.addlast (NewHttprequesthandler ("/ws")); //If the requested endpoint is "/ws", the upgrade handshake is processedPipeline.addlast (NewWebsocketserverprotocolhandler ("/ws")); // //when the connection does not receive a message within 60 seconds, the input triggers a idlestateevent event that is handled by the Heartbeathandler usereventtriggered methodPipeline.addlast (NewIdlestatehandler (Read_idle_time_out, Write_idle_time_out, All_idle_time_out, timeunit.seconds)); Pipeline.addlast (NewTextwebsocketframehandler (group)); }}
Chatserverinitializer.java

tips: above these out of the box is the role of Channelhandler, I do not introduce each one, you can refer to the previous article .

5, Guide class Chatserver

 Public classChatserver {Private FinalChannelgroup Channelgroup =NewDefaultchannelgroup (immediateeventexecutor.instance); Private FinalEventloopgroup Group =NewNioeventloopgroup (); Privatechannel Channel;  Publicchannelfuture Start (inetsocketaddress address) {Serverbootstrap bootstrap=NewServerbootstrap (); Bootstrap.group (Group). Channel (Nioserversocketchannel.class). Childhandler (NewChatserverinitializer (Channelgroup)); Channelfuture channelfuture=Bootstrap.bind (address);        Channelfuture.syncuninterruptibly (); Channel=Channelfuture.channel (); returnchannelfuture; }     Public voiddestroy () {if(Channel! =NULL) {channel.close ();        } channelgroup.close ();    Group.shutdowngracefully (); }     Public Static voidMain (string[] args) {FinalChatserver Chatserver =NewChatserver (); Channelfuture channelfuture= Chatserver.start (NewInetsocketaddress (9999)); //returns the run-time object associated with the current Java applicationRuntime.getruntime (). Addshutdownhook (NewThread () {@Override Public voidrun () {Chatserver.destroy ();        }        });    Channelfuture.channel (). Closefuture (). syncuninterruptibly (); }}
Chatserver.javaThird, the effect shows

Enter http://127.0.0.1:9999 in the browser to see the pre-prepared index.html page; visit ws://127.0.0.1:9999/ws (feel free to find a WebSocket Test tool test) to join the chat room.

A little low chat room is finally finished, is Netty to the HTTP protocol and WebSocket protocol a practice it! Although lack of function, but a journey, a journey! No silicon step, no to thousands of miles, no small stream, no to become Jianghai!

reference:"Netty in ACTION"

Demo Source code:

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.