netty+websocket sending and receiving messages

Premise: when you go to the toilet, there is only one pit, and someone takes it
IO: synchronous blocking (waiting at the door of the toilet, doing nothing, waiting for the person to come out)
NIO: synchronous non blocking (take a cigarette out of the door and go in every now and then to see if the person is out)
AIO: asynchronous non blocking (smoke at the door, the person will inform you after coming out, you can go to the toilet)

  1. Introduce maven dependency
<dependency>
  <groupId>io.netty</groupId>
  <artifactId>netty-all</artifactId>
  <version>4.1.6.Final</version>
</dependency>
  1. Write server code
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class WSServer {

    public static void main(String[] args) {
        // mainGroup is similar to the waiter at the door of the hotel (receiving the link of the client)
        EventLoopGroup mainGroup = new NioEventLoopGroup();
        // Subgroups are similar to staff in hotels. The waiter at the door brings the guests in and leaves them to him
        EventLoopGroup subGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap server = new ServerBootstrap();
            server.group(mainGroup, subGroup)
                    // After opening the room, take the guests upstairs (open a passage)
                    .channel(NioServerSocketChannel.class)
                    // Help the guest to open the door at the door of the room (follow-up processing)
                    .childHandler(new WSServerInitialize());

            ChannelFuture future = server.bind(8088).sync();
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            mainGroup.shutdownGracefully();
            subGroup.shutdownGracefully();
        }
    }

}

  1. Initialize client's link
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 WSServerInitialize extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        // websocket is based on http protocol, so http decoder is needed
        pipeline.addLast(new HttpServerCodec());
        // Support for writing big data stream
        pipeline.addLast(new ChunkedWriteHandler());
        // Aggregate httpMessage into FullHttpRequest or FullHttpResponse
        // This handler is used almost in netty programming
        pipeline.addLast(new HttpObjectAggregator(1024 * 64));

        /**
         * websocket Server processing protocol, used to assign routes to client access: / ws
         * This handler will help you deal with some heavy and complicated things
         * handshaking(ping, pong, close)ping + pong = heartbeat
         * For websocket, it is transmitted through frames, and the frames corresponding to different data types are also different
         */
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));

        // Custom handler
        pipeline.addLast(new ChatHandler());
    }

}
  1. Customizing links for processing clients
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;

import java.time.LocalDateTime;

public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // channel for logging and managing all clients
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame msg) throws Exception {
        // Get the message from the client
        String content = msg.text();
        System.out.println("Data received:" + content);

        for (Channel channel : clients) {
            channel.writeAndFlush(new TextWebSocketFrame("Server side
			[" + LocalDateTime.now() + "]Message received, message:" + content));
        }
    }

    /**
     * After the client connects to the server (open the link)
     * Get the channel of the client and put it into the channelGroup for management
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // When handlerRemoved is triggered, ChannelGroup will automatically remove the channel of the corresponding client
        // clients.remove(ctx.channel());
        System.out.println("Client disconnected, channel Corresponding length ID For:" + ctx.channel().id().asLongText());
        System.out.println("Client disconnected, channel Corresponding short ID For:" + ctx.channel().id().asShortText());
    }
}
  1. Write page tests
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>hello</title>
</head>
<body>
	<div>send message</div>
	<input type="text" id="msgContent">
	<input type="button" value="Click me to send" onclick="CHAT.chat();">
	<div>Receive message:</div>
	<div id="receiveMsg" style="background-color: yellow;"></div>

	<script type="text/javascript">
		window.CHAT = {
			socket: null,
			init: function() {
				if (window.WebSocket) {
					CHAT.socket = new WebSocket("ws://127.0.0.1:8088/ws");
					CHAT.socket.onopen = function() {
						console.log("connect success...");
					},
					CHAT.socket.onclose = function() {
						console.log("connect close...");
					},
					CHAT.socket.onerror = function() {
						console.log("connect error...");
					},
					CHAT.socket.onmessage = function(e) {
						console.log("receive msg: " + e.data);
						var receiveMsg = document.getElementById("receiveMsg");
						var html = receiveMsg.innerHTML;
						receiveMsg.innerHTML = html + "<br />" + e.data;
					}
				} else {
					alert("do not support websocket..");
				}
			},
			chat: function() {
				var msgContent = document.getElementById("msgContent");
				CHAT.socket.send(msgContent.value);
			}
		}
		CHAT.init();
	</script>
</body>
</html>

Tags: Programming Netty socket codec Maven

Posted on Mon, 23 Mar 2020 10:31:02 -0400 by shaneH