Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

Introduction to the

Websocket is an excellent protocol, it is based on TCP, compatible with HTTP network protocol. Through Websocket, we can realize instant communication between the client and the server, eliminating the performance loss caused by the client’s multiple round robin.

Since webSocket is so good, how to use webSocket in Netty?

In the netty websocket

Although Websocket is a separate and completely different protocol from HTTP, it is included in HTTP packages in Netty. Consider the support for various protocols in Netty. If you want to support this protocol, you definitely need a decoder and encoder and decoder to encode and decode the protocol. Converts transferred data from ByteBuf to the protocol type, or from the protocol type to ByteBuf.

This is the core working principle of NetTY and the basis for subsequent custom Netty extensions.

So what about websocket?

The version of the websocket

WebSocket as a protocol, naturally not out of thin air, through continuous development to today’s WebSocket protocol. We won’t go into the history of webSocket specifically. Let’s take a look at the various WebSocket versions offered by Netty.

In the WebSocketVersion class, we can see:

UNKNOWN(AsciiString.cached(StringUtil.EMPTY_STRING)),

    V00(AsciiString.cached("0")),

    V07(AsciiString.cached("7")),

    V08(AsciiString.cached("8")),

    V13(AsciiString.cached("13"));
Copy the code

WebSocketVersion is an enumerated type that defines four versions of WebSocket. In addition to UNKNOWN, there are versions 0, 7, 8, and 13 of webSocket.

FrameDecoder and FrameEncoder

We know that webSocket messages are sent through frames, because different versions of Websocket affect the format of frames. So we need different framedecoders and FrameEncoder to convert between WebSocketFrame and ByteBuf.

Since there are four versions of WebSocket, there are four versions of decoder and encoder:

WebSocket00FrameDecoder
WebSocket00FrameEncoder
WebSocket07FrameDecoder
WebSocket07FrameEncoder
WebSocket08FrameDecoder
WebSocket08FrameEncoder
WebSocket13FrameDecoder
WebSocket13FrameEncoder
Copy the code

As for the frame differences between each version, we will not elaborate here, interested friends can follow my subsequent articles.

Those familiar with Netty should know that both Encoder and decoder are used to convert messages in channel. What about websocket support in Netty?

WebSocketServerHandshaker

Netty provides a unified WebSocketServerHandshaker class to use the encoder and decoder use. Netty provides a factory class WebSocketServerHandshakerFactory according to client request header websocket version is different, different WebSocketServerHandshaker to return.

public WebSocketServerHandshaker newHandshaker(HttpRequest req) { CharSequence version = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_VERSION); if (version ! = null) { if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) { // Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification). return new WebSocketServerHandshaker13( webSocketURL, subprotocols, decoderConfig); } else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) { // Version 8 of the wire protocol - version 10 of  the draft hybi specification. return new WebSocketServerHandshaker08( webSocketURL, subprotocols, decoderConfig); } else if (version.equals(WebSocketVersion.V07.toHttpHeaderValue())) { // Version 8 of the wire protocol - version 07 of  the draft hybi specification. return new WebSocketServerHandshaker07( webSocketURL, subprotocols, decoderConfig); } else { return null; } } else { // Assume version 00 where version header was not specified return new WebSocketServerHandshaker00(webSocketURL, subprotocols, decoderConfig); }}Copy the code

Similarly, we can see, netty for websocket also defines four different WebSocketServerHandshaker.

Defined WebSocketServerHandshaker handleshake method, by passing in the channel, and add to its encoder and decoder

public final ChannelFuture handshake(Channel channel, FullHttpRequest req,
                                            HttpHeaders responseHeaders, final ChannelPromise promise) 

            p.addBefore(ctx.name(), "wsencoder", newWebSocketEncoder());
            p.addBefore(ctx.name(), "wsdecoder", newWebsocketDecoder());
Copy the code

And add the two newWebSocketEncoder and newWebsocketDecoder is defined in the specific implementation of each WebSocketServerHandshaker.

WebSocketFrame

All ecodes and decode are converted in WebSocketFrame and ByteBuf. WebSocketFrame inherits from DefaultByteBufHolder, indicating that it is a container for ByteBuf. In addition to holding ByteBuf, it has two additional properties, namely finalFragment and RSV.

FinalFragment Indicates whether the frame is the last frame. This property is particularly useful for large data volume messages that split the message into different frames.

Let’s look at the format of the WebSocket protocol message:

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len==126/127) | | |1|2|3| |K| | | +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + | Extended payload length continued, if payload len == 127 | + - - - - - - - - - - - - - - - +-------------------------------+ | |Masking-key, if MASK set to 1 | +-------------------------------+-------------------------------+ | Masking-key (continued) | Payload  Data | +-------------------------------- - - - - - - - - - - - - - - - + : Payload Data continued ... : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data continued ... | +---------------------------------------------------------------+Copy the code

RSV represents the extended fields in the message, namely RSV1,RSV2, and RSV3.

Beyond that, there are some basic operations for ByteBuf.

WebSocketFrame is an abstract class that implements the following classes:

BinaryWebSocketFrame
CloseWebSocketFrame
ContinuationWebSocketFrame
PingWebSocketFrame
PongWebSocketFrame
TextWebSocketFrame
Copy the code

BinaryWebSocketFrame and TextWebSocketFrame are well understood because they represent the two ways messages are transmitted.

CloseWebSocketFrame is the frame that represents closing the connection. ContinuationWebSocketFrame said in a message than a frame said.

PingWebSocketFrame and PongWebSocketFrame are two special frames that are mainly used for server and client probes.

These frames are one-to-one corresponding to the message type of Websocket. It is helpful to understand the message type of Websocket to understand these frame classes.

Websocket is used in Netty

Talk about so many websocket principles and implementation classes, the next is the actual combat.

In this example, we use Netty to create a WebSocket Server and then use a browser client to access the server.

The process of creating a WebSocket Server is no different from that of a normal Netty server. Just add a custom WebSocketServerHandler to the ChannelPipeline:

pipeline.addLast(new WebSocketServerHandler());
Copy the code

What does this WebSocketServerHandler need to do?

It needs to handle both normal HTTP requests and webSocket requests.

The two types of requests can be identified by the difference in the type of MSG received:

Public void channelRead0(ChannelHandlerContext CTX, Object MSG) throws IOException {// Based on the message type, If (MSG instanceof FullHttpRequest) {handleHttpRequest(CTX, (FullHttpRequest) MSG); } else if (msg instanceof WebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); }}Copy the code

Before the client can make a Websocket connection, it needs to borrow the current channel and enable Handleshake:

/ / the websocket handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory ( getWebSocketLocation(req), null, true, 5 * 1024 * 1024); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); }Copy the code

Once we have the handshaker, we can process the subsequent WebSocketFrame:

private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame) {if (frame instanceof CloseWebSocketFrame) {handshaker.close(CTX, (CloseWebSocketFrame) frame.retain()); return; } if (frame instanceof PingWebSocketFrame) { ctx.write(new PongWebSocketFrame(frame.content().retain())); return; } if (frame Instanceof TextWebSocketFrame) {// Return ctx.write(frame.retain()); return; } if (frame Instanceof BinaryWebSocketFrame) {// Return ctx.write(frame.retain()); }}Copy the code

Here we just return the message mechanically, and you can parse the message according to your business logic.

With the server side, how does the client connect? It’s easy to construct a WebSocket object first and then handle the various callbacks:

The socket = new WebSocket (ws: / / "127.0.0.1:8000 / WebSocket"); socket.onmessage = function (event) { } socket.onopen = function(event) { }; socket.onclose = function(event) { };Copy the code

conclusion

The above is the complete process of using Netty to build a Websocket server. The server in this paper can handle ordinary HTTP requests and Websocket requests at the same time, but it is slightly complicated. Is there a simpler way? Stay tuned.

Learn -netty4 for an example of this article

This article is available at www.flydean.com/23-netty-we…

The most popular interpretation, the most profound dry goods, the most concise tutorial, many tips you didn’t know waiting for you to discover!

Welcome to pay attention to my public number: “procedures those things”, understand technology, more understand you!