Use of WebSocket server in Netty

WebSocket before we introduce the integrated SpringBoot carried out to achieve, here we take a look at Netty WebSocket is how, in fact, is relatively simple, according to first before we can achieve Http server and client using Netty , we A simple page is used to make a request to the client, and its page content is as follows:
Insert picture description here

Very simple, it is a div area for displaying information below the input box and a button for sending a message, then we are also related to this page WebSocket way, here we realize chat native WebSocket API also introduces However, here is mainly in the onmessage method, when the message is received, it is displayed on the page, as follows:
Insert picture description here

Then we are our message sending event, as follows:
Insert picture description here

The above is the entire content of chat.html, we put it in the project, we can make a request on the page
Insert picture description here


Then the server is the standard Netty startup process, and some SSL related support is added during startup. This is also introduced when we implement the Http server, as follows:

public final class WebSocketServer {

    private static boolean SSL = false;
    public static final int PORT = SSL ? 8443 : 8080;

    private void start() throws Exception {
        final SslContext sslContext;
        if (SSL) {
            SelfSignedCertificate signedCertificate = new SelfSignedCertificate();
            sslContext = SslContextBuilder.forServer(signedCertificate.certificate(),
                    signedCertificate.privateKey()).build();
        } else {
            sslContext = null;
        }

        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {
            serverBootstrap.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 512)
                    .childHandler(new WebSocketServerInitializer(sslContext));

            ChannelFuture channelFuture = serverBootstrap.bind(PORT).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        WebSocketServer server = new WebSocketServer();
        server.start();
    }
}

Then we need to take a look at the related Handler we added, which needs to add related SSL support and Http support. We also said before that WebSocket is built based on Http, and then we also set the path of WebSocket The path is the same as the path we requested in JS, and then add related WebSocket support, as follows:
Insert picture description here
Insert picture description here


Then what we need appropriate treatment and WebSocket request Http request, where the request for Http main thing is to chat.html page back to the browser for display, here and use Netty achieve Http server and client is almost Consistent
Insert picture description here

public class WebPageHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        // 状态为1xx的话,继续请求
        if(HttpUtil.is100ContinueExpected(request)){
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
            ctx.writeAndFlush(response);
        }

        //处理错误或者无法解析的http请求
        if (!request.decoderResult().isSuccess()) {
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST,
                    Unpooled.copiedBuffer("请求失败", CharsetUtil.UTF_8));

            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8");
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }

        //只允许GET请求
        if (request.method() != HttpMethod.GET) {
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN);

            ByteBuf byteBuf = Unpooled.copiedBuffer("只允许GET请求", CharsetUtil.UTF_8);
            response.content().writeBytes(byteBuf);
            byteBuf.release();

            HttpUtil.setContentLength(response, response.content().readableBytes());
            ctx.channel().writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }

        if ("/chat".equals(request.uri())) {
            String path = this.getClass().getClassLoader().getResource("static/chat.html").getPath();
            RandomAccessFile file = new RandomAccessFile(path, "r");

            HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=UTF-8");

            if (HttpUtil.isKeepAlive(request)) {
                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, file.length());
                response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.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 channelFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
            if (!HttpUtil.isKeepAlive(request)) {
                channelFuture.addListener(ChannelFutureListener.CLOSE);
            }
        } else {
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND,
                    Unpooled.copiedBuffer("访问路径错误", CharsetUtil.UTF_8));

            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8");
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }
    }
}

Finally, we mainly need to look at the processing of related WebSocket requests, as follows:
Insert picture description here

public class WebSocketHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
        if (msg instanceof TextWebSocketFrame) {
            //判断是否为文本帧,若是则进行处理
            String data = ((TextWebSocketFrame) msg).text();
            ctx.channel().writeAndFlush(new TextWebSocketFrame(data));
        }
    }
}

Here we briefly introduce TextWebSocketFrame , the WebSocket RFC issued by IETF, which defines six frames, Netty provides a POJO implementation for each of them. Let ’s take a look at six different types of WebSocketFrame, the first three are data frames , The last three are control frames, the last two frames are heartbeat packets, ping initiates heartbeat, and pong responds to heartbeat.

Frame type description
BinaryWebSocketFrame Contains binary data
TextWebSocketFrame Contains text data
ContinuationWebSocketFrame Contains text data or binary data belonging to the previous BinaryWebSocketFrame or TextWebSocketFrame
CloseWebSocketFrame Indicates a CLOSE request, including a closed status code and reason for closing
PingWebSocketFrame Request to transmit a PongWebSocketFrame
PongWebSocketFrame Sent as a response to PingWebSocketFrame

The following is the result of its operation. Enter the relevant information in the input box and click Send. It will be sent to the server through WebSocket, and then the server will return the message, as shown below:
Insert picture description here

Although the above implemented functions are the same as our previous ones, the implementation is different. We can find the displayed message through WebSoket through the front-end JS code.


Below we make a simple modification, and can also achieve the function of mass sending. We also define an event to remind other clients that a new client logs in to proceed as follows:
Insert picture description here
Insert picture description here

286 original articles published · Liked12 · Visitors 10,000+

Guess you like

Origin blog.csdn.net/newbie0107/article/details/104594237