Netty Authoritative Guide 2nd edition learning notes 11--implementation WebSocket

Source: Internet
Author: User
Tags throwable
Getting started with WebSocket

WebSocket is a network technology that HTML5 provides for full-duplex communication between browsers and services, and the WebSocket Communication protocol was established as the standard Rfc6455,websocket API by the IETF in 2011.
In the WebSocket API, the browser and the server only need to do a handshake action, then the browser and the server formed a fast channel, the two can directly transmit data to each other. WebSocket is based on TCP bidirectional Full-duplex for message delivery. Single TCP connection, full duplex mode communication for proxy, firewall and router transparent without header information, cookies, and authentication without security overhead the link activation server can transmit messages to the client WebSocket the connection is established by Ping/pong frame


When establishing a websocket connection, a handshake request is made through the client or the browser, requesting information such as:

Get/chat http/1.1
Host:server.com
upgrade:websocket
connection:upgrade
sec-websocket-key: dghiihnbxbszsbub25jzq==
origin:http://test.com
sec-websocket-protocal:chat, Superchat
Sec-websocket-version:13

The client first initiates an HTTP request to the server, which, unlike the usual HTTP request, contains additional header information in which the additional header information "Upgrade:websocket" indicates that it is an HTTP request for a protocol upgrade. The server side resolves additional header information, and then generates an answer message to return to the client. The WebSocket connection between the client and the server is established.
Service-Side Answer example:

http/1.1 switching Protocols
upgrade:websocket
connection:upgrade
sec-websocket-accept: s3pplmbitxaq9kygzzhzrbk+xoo=
Sec-websocket-protocal:chat

The Sec-websocket-key in the request message is random, and the server side uses the data to construct a SHA-1 summary of the information. "Sec-websocket-key" plus the Magic string "258eafa5-e914-47da-95ca-c5ab0dc85b11", using SHA-1 encryption, and then BASE-64 encoded, the result as " Sec-websocket-accept the value of the header, which is returned to the client. WebSocket life cycle

Slightly... WebSocket Connection Shutdown

Slightly... Netty WebSocket Protocol Development WebSocket Service-side development

When the WebSocket server receives the request message, it first judges the type of the message, and if it is not a websocket handshake request message, returns the HTTP bad requests response to the client, an example of the client's handshake request message:

Defaultfullhttprequest, decoderesult:success)
get/websocket http/1.1
upgrade:websocket
Connection: Upgrade
host:localhost:8080
origin:http://localhost:8080
sec-websocket-key:qwor7m5rbsgzza8ut8bc5a= =
sec-websocket-version:13
sec-websocket-extensions:x-webkit-deflate-frame
content-length:0

The service side handles the handshake request message, constructs the handshake response return, and the socket connection between the two sides is formally established.
After the connection is established, both parties can actively send messages to each other until they are closed. Code Implementation Chat Room sample

Httprequesthandler

Import Java.io.File;
Import Java.io.RandomAccessFile;
Import java.net.URISyntaxException;
Import Java.net.URL;
Import Io.netty.channel.Channel;
Import Io.netty.channel.ChannelFuture;
Import Io.netty.channel.ChannelFutureListener;
Import Io.netty.channel.ChannelHandlerContext;
Import io.netty.channel.DefaultFileRegion;
Import Io.netty.channel.SimpleChannelInboundHandler;
Import Io.netty.handler.codec.http.DefaultFullHttpResponse;
Import Io.netty.handler.codec.http.DefaultHttpResponse;
Import Io.netty.handler.codec.http.FullHttpRequest;
Import Io.netty.handler.codec.http.FullHttpResponse;
Import Io.netty.handler.codec.http.HttpHeaders;
Import Io.netty.handler.codec.http.HttpResponse;
Import Io.netty.handler.codec.http.HttpResponseStatus;
Import io.netty.handler.codec.http.HttpVersion;
Import io.netty.handler.codec.http.LastHttpContent;
Import Io.netty.handler.ssl.SslHandler;

Import Io.netty.handler.stream.ChunkedNioFile; public class Httprequesthandler extends Simplechannelinboundhandler<fullhttprequest> {private final String Wsuri;

    private static final File INDEX;
        static {URL location = HttpRequestHandler.class.getProtectionDomain (). Getcodesource (). GetLocation ();
            try {String path = Location.touri () + "websocketchatclient.html"; Path =!path.contains ("file:")?
            Path:path.substring (5);
        INDEX = new File (path); The catch (URISyntaxException e) {throw new IllegalStateException ("Unable to locate websocketchatclient.html")
        e);
    } public Httprequesthandler (String wsuri) {This.wsuri = Wsuri; private static void Send100continue (Channelhandlercontext ctx) {fullhttpresponse response = new defaultful
        Lhttpresponse (Httpversion.http_1_1, httpresponsestatus.continue);
    Ctx.writeandflush (response); @Override public void Exceptioncaught (Channelhandlercontext ctx, Throwable cause) throws Exception {Ch Annel incoming= Ctx.channel ();
        System.out.println ("Client:" +incoming.remoteaddress () + "abnormal");
        Closes the connection cause.printstacktrace () when there is an exception;
    Ctx.close (); 
        @Override protected void messagereceived (Channelhandlercontext ctx, fullhttprequest request) throws Exception {
        if (Wsuri.equalsignorecase (Request.geturi ())) {Ctx.firechannelread (Request.retain ());
             else {/** * Continue * HTTP client program has a body part of an entity to be sent to the server, but would like to see if the server before sending will * Accept this entity, so before sending an entity, a request to carry the expect request header of continue is sent.
             After the server receives such a request, it should respond with a continue or an error code.
            */if (httpheaders.is100continueexpected (Request)) {send100continue (CTX);

            } randomaccessfile File = new Randomaccessfile (INDEX, "R");
            HttpResponse response = new Defaulthttpresponse (Request.getprotocolversion (), Httpresponsestatus.ok); Response.headers (). Set (HttpheadeRs. Names.content_type, "text/html;

            Charset=utf-8 ");

            Boolean keepAlive = httpheaders.iskeepalive (request);
                if (keepAlive) {response.headers (). Set (HttpHeaders.Names.CONTENT_LENGTH, File.length ());
            Response.headers (). Set (HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);

            } ctx.write (response); if (Ctx.pipeline (). Get (Sslhandler.class) = null) {Ctx.write (New Defaultfileregion (File.getchannel (), 0,
            File.length ()));
            else {ctx.write (new Chunkedniofile (File.getchannel ()));
            } channelfuture Future = Ctx.writeandflush (lasthttpcontent.empty_last_content);
            if (!keepalive) {Future.addlistener (channelfuturelistener.close);
        } file.close (); }


    }
}
Textwebsocketframehandler
Import Io.netty.channel.Channel;
Import Io.netty.channel.ChannelHandlerContext;
Import Io.netty.channel.SimpleChannelInboundHandler;
Import Io.netty.channel.group.ChannelGroup;
Import Io.netty.channel.group.DefaultChannelGroup;
Import Io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

Import Io.netty.util.concurrent.GlobalEventExecutor; public class Textwebsocketframehandler extends simplechannelinboundhandler<textwebsocketframe> {public static C

    Hannelgroup channels = new Defaultchannelgroup (globaleventexecutor.instance); @Override public void handleradded (Channelhandlercontext ctx) throws Exception {Channel incoming = Ctx.channe
        L (); for (Channel channel:channels) {Channel.writeandflush (New Textwebsocketframe ("[SERVER]-" + Incoming.remot
        Eaddress () + "add"));
        } channels.add (Ctx.channel ());
    System.out.println ("Client:" +incoming.remoteaddress () + "add"); } @Override public void handlerremoved(Channelhandlercontext ctx) throws Exception {Channel incoming = Ctx.channel (); for (Channel channel:channels) {Channel.writeandflush (New Textwebsocketframe ("[SERVER]-" + Incoming.remot
        Eaddress () + "Leave");
        System.out.println ("Client:" +incoming.remoteaddress () + "Leave");
    Channels.remove (Ctx.channel ()); @Override public void channelactive (Channelhandlercontext ctx) throws Exception {Channel incoming = ct
        X.channel ();
    System.out.println ("Client:" +incoming.remoteaddress () + "online"); @Override public void channelinactive (Channelhandlercontext ctx) throws Exception {Channel incoming =
        Ctx.channel ();
    System.out.println ("Client:" +incoming.remoteaddress () + "off line"); @Override public void Exceptioncaught (Channelhandlercontext ctx, Throwable cause) throws Exception {Ch
        Annel incoming = Ctx.channel (); System.out.println ("Client:" +incoming.remoteaddress () + "Exception ");
        Closes the connection cause.printstacktrace () when there is an exception;
    Ctx.close ();
        } @Override protected void messagereceived (Channelhandlercontext ctx,textwebsocketframe msg) throws Exception {
        Channel incoming = Ctx.channel (); for (Channel channel:channels) {if (Channel!= incoming) {Channel.writeandflush (new Textweb
            Socketframe ("[" + incoming.remoteaddress () + "]" + Msg.text ()));
            else {Channel.writeandflush (new Textwebsocketframe ("[You]" + msg.text ()); }
        }

    }

}
Websocketchatserver
Import Io.netty.bootstrap.ServerBootstrap;
Import Io.netty.channel.ChannelFuture;
Import io.netty.channel.ChannelOption;
Import Io.netty.channel.EventLoopGroup;
Import Io.netty.channel.nio.NioEventLoopGroup;

Import Io.netty.channel.socket.nio.NioServerSocketChannel;
    public class Websocketchatserver {private int port;
    public websocketchatserver (int port) {this.port = port;
        public void Run () throws Exception {Eventloopgroup bossgroup = new Nioeventloopgroup ();
        Eventloopgroup Workergroup = new Nioeventloopgroup ();
            try {serverbootstrap b = new Serverbootstrap (); B.group (Bossgroup, Workergroup). Channel (Nioserversocketchannel.class). Childhandler (New Websock Etchatserverinitializer ()). Option (Channeloption.so_backlog, 128). Childoption (Channeloption.so_

            KEEPALIVE, True);

            System.out.println ("websocketchatserver start");
   Binding ports, starting to receive incoming connections         Channelfuture f = b.bind (port). sync ();

        Wait for the server socket to close F.channel (). Closefuture (). sync ();
            finally {workergroup.shutdowngracefully ();

            Bossgroup.shutdowngracefully ();
        System.out.println ("Websocketchatserver close");
        } public static void Main (string[] args) throws Exception {int port;
        if (Args.length > 0) {port = Integer.parseint (Args[0]);
        else {port = 8888;

    New Websocketchatserver (port). Run (); }
}
Websocketchatserverinitializer
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline;
Import Io.netty.channel.socket.SocketChannel;
Import Io.netty.handler.codec.http.HttpObjectAggregator;
Import Io.netty.handler.codec.http.HttpServerCodec;
Import Io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

Import Io.netty.handler.stream.ChunkedWriteHandler; public class Websocketchatserverinitializer extends channelinitializer<socketchannel> {@Override public voi

        D initchannel (Socketchannel ch) throws Exception {Channelpipeline pipeline = Ch.pipeline ();
        Pipeline.addlast (New Httpservercodec ());
        Pipeline.addlast (New Httpobjectaggregator (64*1024));
        Pipeline.addlast (New Chunkedwritehandler ());
        Pipeline.addlast (New Httprequesthandler ("/ws"));
        Pipeline.addlast (New Websocketserverprotocolhandler ("/ws"));

    Pipeline.addlast (New Textwebsocketframehandler ()); }
}
HTML
<! DOCTYPE html>

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.