Netty With WebSocket

In the last article, we discussed how to use Netty to develop an Http file server, which contains information about how to use Netty provided component classes to parse the Http protocol for processing requests, and then continue to use existing components for encoding and decoding and transmission.

This article is mainly about how to use Netty integration WebSocket to do a DEMO article. In fact, Netty, like Http, provides some handy components for WebSocket encapsulation that you can use just by coding. At this point, I once again experienced Netty’s high scalability.

Then, this article will talk about the content

  1. What is theWebSocket.
  2. WebSocketHttpThe difference between.
  3. Why do we needWebSocket.
  4. NettyWebSocketIntegration between.

What is theWebSocket

That’s how most people describe it

WebSocket is a network technology of full duplex communication between browser and server provided by HTML5.

It’s kind of hard to understand. HTML5 we understand, but full-duplex communication we don’t. So let’s try to figure out what a WebSocket is.

According to our previous study, we know that Socket is a functional interface between the transport layer and the application. Through these interfaces, we can use the TCP/IP protocol stack to send and receive data at the transport layer. So what does WebSocket have to do with this? From the literal meaning of WebSocket, we can split called Web and Socket. Maybe you can GET it, isn’t WebSocket like running on the Web, responsible for the Http Socket communication specification?

I really do! WebSocket is a Socket communication specification based on Http protocol. It provides functions similar to TCP Socket. Like TCP Socket, WebSocket can call the lower protocol stack and send and receive data arbitrarily. But don’t think of WebSocket as an upgrade to Http (for reasons explained below). In fact, WebSocket is a lightweight network communication protocol based on TCP, which is on a par with Http.

Why do we needWebSocket ?

First of all, we need to understand that the emergence of new things in the same field is most likely not to overturn the former, but to continue to improve on the shoulders of giants. The emergence of WebSocket, in fact, is to make up for the shortcomings of Http.

According to WebSocket, we know that it is a network technology of full duplex communication. Http is a half duplex technology. Http has two characteristics under this technology

  1. Only one-way data flows can be allowed between the client and server at the same time
  2. The server cannot actively send data to the client, but can only “passively” respond to requests from the client in request-reply mode.

What kind of problems would a half-double bring us? If you’ve ever done real-time messaging, you’re probably more frustrated. Generally speaking, real-time communication requires mutual interaction, that is, you give it to him, he gives it to you. However, it is obvious that half-duplex can only be sent from the client to the server, but not from the server to the client. You might say, well, can’t my client ask the server every once in a while?

In real time, in the absence of Websockets, a “polling” approach is generally used to achieve even communication, that is, continuous requests to the server. If the frequency of polling is high, the effect of real-time communication can be achieved approximately

However, the disadvantages of polling are also obvious, repeatedly sending invalid query requests consumes a lot of bandwidth and CPU resources, which is very uneconomical.

So, WebSocket is full duplex communication.

WebSocketThe characteristics of

Maybe a lot of people have a question: obviously I see WebSocket is based on Http interaction, its protocol format is not similar to Http place? Well, not really. We know that Http is the current Internet communication protocol, there is no other. But WebSocket doesn’t follow a lot of Http. Instead, it has the following features

  1. First of all,WebSocketA binary frame structure is used, withHttpThe structure of is completely different. But in order to be able to facilitate the promotion and application, have to take a “free ride” in the use of habits as far as possibleHttpClose up. That’s what it’s calledWebThe meaning of. (I’ll explain why this is hitchhiking below)
  2. Second,WebSocketDidn’t likeSocketuseIP + portBut in the same wayHttpURIFormat. butURLThe beginning is notHttp, butwswss, are plaintext and encrypted respectivelyWebSocketThe agreement.
  3. In addition,WebSocketThe default port is still used80443. Because the current server firewall on the Internet blocks most of the ports, only onHttp80443Release, soWebSocketYou cancamouflageintoHttpAgreement tothroughFirewall, establish a connection with the server.

WebSocket interaction process

While talking about WebSocket features, you may have learned a little bit about WebSocket: WebSocket actually has little to do with Http, but WebSocket thrives on the popularity of Http.

No hurry, let’s take a look at the order of WebSocket interaction. Here is an interactive diagram of the overall picture:

As we have seen, WebSocket also has a TCP handshake process. It first issues an Http Get request, which is detailed below

GET /HTTP/1.1
Upgrader: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Set-WebSocket-Key: sNNdMgdc2VGJEKS
Set-WebSocket-Version: 13
Copy the code

In the message, we should pay attention to several fields

The field name use
Upgrade Set toWebSocketIs required to explain to the serverHttpUpgrade toWebSocketagreement
Sec-WebSocket-key Base64Encoded 16-byte random number used to verify whetherWebSocketRather thanHttpagreement
Sec-WebSocket-Version Said the use ofWebSocketProtocol Version number

Then, when the server receives the packet from the client, it parses the packet. At this point it knows from the message that this is a WebSocket request. Therefore, it starts to construct special message information. The content of the message is

HTTP/1.1 101 Switching Protocols
Upgrader: websocket
Connection: Upgrade
Set-WebSocket-Accept: fFBooB7FAkKLlXgrSz0BT3v4hq5s
Set-WebSocket-Location: ws://examples.com/
Copy the code

The fields of the packet are still familiar. However, we found a description of 101 Switching Protocols, which is a 101 status code returned by the server telling the client that WebSocket full-duplex bidirectional communication is possible. This means that the client and server have agreed to use WebSocket to interact with each other. Http is no longer a problem.

Set-websocket-accept is used to verify the client request message and also to prevent misconnections. This is done by assigning the client set-websocket-key to a dedicated UUID and then calculating the SHA-1 digest. In this case, the client also compares the response information of the server through such calculation to avoid authentication failure.

After the handshake is complete, the subsequent data is no longer Http packets, but binary frames in WebSocket format.

NettyintegrationWebSocket

First again, we use Netty to implement a server startup class

WebSocketServer.java

public class WebSocketServer {
    public void run(int port) throws Exception {
	EventLoopGroup bossGroup = new NioEventLoopGroup();
	EventLoopGroup workerGroup = new NioEventLoopGroup();
	try {
	    ServerBootstrap b = new ServerBootstrap();
	    b.group(bossGroup, workerGroup)
		    .channel(NioServerSocketChannel.class)
		    .childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel ch)
				throws Exception {
                     // HTTP decoder
			    ChannelPipeline pipeline = ch.pipeline();
			    pipeline.addLast("http-codec".new HttpServerCodec());
                    // Is responsible for putting Http information such as version
                    // Inherits a FullHttpRequesst from the Http content
			    pipeline.addLast("aggregator".new HttpObjectAggregator(65536));
                    // Large file write class
			    ch.pipeline().addLast("http-chunked".new ChunkedWriteHandler());
                    // WebSocket handles the class
			    pipeline.addLast("handler".newWebSocketServerHandler()); }});// Listen on the port
	    Channel ch = b.bind(port).sync().channel();
	    ch.closeFuture().sync();
	} finally{ bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); }}public static void main(String[] args) throws Exception {
	    new WebSocketServer().run(8080); }}Copy the code

Next, we is to realize the processing logic processor WebSocketServerHandler. Java

public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
    private static final Logger logger = Logger
	    .getLogger(WebSocketServerHandler.class.getName());
        
    private WebSocketServerHandshaker handshaker;

    @Override
    public void messageReceived(ChannelHandlerContext ctx, Object msg)
	    throws Exception {
	// Traditional HTTP access (the handshake process goes here)
	if (msg instanceof FullHttpRequest) {
	    handleHttpRequest(ctx, (FullHttpRequest) msg);
	}
	/ / the WebSocket connection
	else if (msg instanceofWebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); }}@Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
	ctx.flush();
    }

    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {

	// If HTTP decoding fails, an HHTP exception is returned
	if(! req.getDecoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) {
	    sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
		    BAD_REQUEST));
	    return;
	}

	// Construct the handshake response return, currently the address of the machine
	WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
		"ws://localhost:8080/websocket".null.false);
	handshaker = wsFactory.newHandshaker(req);
	if (handshaker == null) {
	    WebSocketServerHandshakerFactory
		    .sendUnsupportedWebSocketVersionResponse(ctx.channel());
	} else{ handshaker.handshake(ctx.channel(), req); }}private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {

	// Check whether it is the command to close the link
	if (frame instanceof CloseWebSocketFrame) {
	    handshaker.close(ctx.channel(),
		    (CloseWebSocketFrame) frame.retain());
	    return;
	}

	// Check whether it is a Ping message
	if (frame instanceof PingWebSocketFrame) {
	    ctx.channel().write(
		    new PongWebSocketFrame(frame.content().retain()));
	    return;
	}

	// This routine only supports text messages, not binary messages
	if(! (frameinstanceof TextWebSocketFrame)) {
	    throw new UnsupportedOperationException(String.format(
		    "%s frame types not supported", frame.getClass().getName()));
	}

	// Return the reply message
	String request = ((TextWebSocketFrame) frame).text();
	if (logger.isLoggable(Level.FINE)) {
	    logger.fine(String.format("%s received %s", ctx.channel(), request));
	}

	ctx.channel().write(
		new TextWebSocketFrame(request
			+ ", welcome to Netty WebSocket service, now:
			+ new java.util.Date().toString()));
    }

    private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
	// Return the reply to the client
	if(res.getStatus().code() ! =200) {
	    ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),
		    CharsetUtil.UTF_8);
	    res.content().writeBytes(buf);
	    buf.release();
	    setContentLength(res, res.content().readableBytes());
	}

	// If it is not keep-alive, close the connection
	ChannelFuture f = ctx.channel().writeAndFlush(res);
	if(! isKeepAlive(req) || res.getStatus().code() ! =200) { f.addListener(ChannelFutureListener.CLOSE); }}@Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
	    throws Exception { cause.printStackTrace(); ctx.close(); }}Copy the code

In fact, the above code is relatively clear. It is mainly divided into two treatments:

methods instructions
handleHttpRequest() Responsible for responding to client handshake requests
handleWebSocketFrame() Responsible for handlingWebSocketThe news of the

While handling handleWebSocketFrame() is responsible for several operations:

  1. Whether the command is to close the link
  2. Is it a heartbeat message?
  3. Whether message content

conclusion

This article was originally intended to talk about Netty and WebSocket integration. But I found that the growth of WebSocket and the reasons behind its popularity are far from as simple as imagined. So I decided to dig a little deeper. Summarize what has been said in the passage

  1. WebSocketThe equivalent ofHttpA long-link patch for the protocol. It andHttpExisting commonalities (connection handshake useGetRequest), the first is to solveHttpThe problem of not supporting long connections has been resolvedHttpShort link features that do not meet requirements.
  2. On the internal structure,WebSocketHttpThere are numerous differences. In order to improve efficiency,WebSocketWith binary frames, it is easier to understand and transfer.
  3. useNettyPackaged processors can be implemented quicklyWebSocketThe application of

The end!