netty整合websocket(完美教程)

websocket的介绍:

WebSocket是一种在网络通信中的协议,它是独立于HTTP协议的。该协议基于TCP/IP协议,可以提供双向通讯并保有状态。这意味着客户端和服务器可以进行实时响应,并且这种响应是双向的。WebSocket协议端口通常是80,443。

WebSocket的出现使得浏览器具备了实时双向通信的能力。与HTTP这种非持久单向响应应答的协议相比,WebSocket是一个持久化的协议。举例来说,即使在关闭网页或者浏览器后,WebSocket的连接仍然保持,用户也可以继续接收到服务器的消息。

此外,要建立WebSocket连接,需要浏览器和服务器握手进行建立连接。一旦连接建立,WebSocket可以在浏览器和服务器之间双向发送或接受信息。总的来说,WebSocket提供了一个高效、实时的双向通信方案。

1、用netty构建websocket服务器

复制代码
package org.tianfan.websocket;// WebSocketServer.java

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

public class WebSocketServer {

    private final int port;

    public WebSocketServer(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 ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     p.addLast(new HttpServerCodec());
                     p.addLast(new HttpObjectAggregator(65536));
                     p.addLast(new WebSocketServerProtocolHandler("/websocket"));
                     p.addLast(new WebSocketServerHandler());
                 }
             });

            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }

        new WebSocketServer(port).run();
    }
}

我来解释一下上面的代码:

  • p.addLast(new HttpServerCodec()):添加HTTP服务器编解码器,用于将数据转换成HTTP协议格式进行传输。
  • p.addLast(new HttpObjectAggregator(65536)):添加HTTP对象聚合处理器,用于将HTTP请求或响应中的多个消息片段聚合成完整的消息。
  • p.addLast(new WebSocketServerProtocolHandler("/websocket")):添加WebSocket协议处理器,用于处理WebSocket握手、消息传输等操作。
  • p.addLast(new WebSocketServerHandler()):添加WebSocket处理器,用于处理客户端与服务器端之间的数据交换,实现自定义的业务逻辑。

使用Netty框架中的WebSocketServerProtocolHandler处理器,将HTTP升级为WebSocket协议。它创建了一个新的管道(pipeline)并将WebSocket处理程序添加到管道的尾部,以便处理WebSocket协议的握手和帧。"/websocket"是WebSocket的URI路径,它指定了WebSocket服务的相对地址,该地址将在客户端请求连接时被指定。

复制代码
package org.tianfan.websocket;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

public class WebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    @Override
    public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 处理消息
        System.out.println("Received message: " + msg.text());
        ctx.channel().writeAndFlush(new TextWebSocketFrame("Server received: " + msg.text()));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 添加连接
        System.out.println("Client connected: " + ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 断开连接
        System.out.println("Client disconnected: " + ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 异常处理
        cause.printStackTrace();
        ctx.close();
    }
}

我来解释一下上面的代码:

刚信息发过来的时候,在服务端打印,并写入前端。

2、前端客户端页面:

复制代码
<!-- index.html -->

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Test</title>
</head>
<body>
    <h1>WebSocket Test</h1>
    <div>
        <input type="text" id="message" placeholder="Message">
        <button onclick="send()">Send</button>
    </div>
    <div id="output"></div>
    <script>
        var socket = new WebSocket("ws://localhost:8080/websocket");

        socket.onopen = function(event) {
            console.log("WebSocket opened: " + event);
        };

        socket.onmessage = function(event) {
            console.log("WebSocket message received: " + event.data);
            var output = document.getElementById("output");
            output.innerHTML += "<p>" + event.data + "</p>";
        };

        socket.onclose = function(event) {
            console.log("WebSocket closed: " + event);
        };

        function send() {
            var message = document.getElementById("message").value;
            socket.send(message);
        }
    </script>
</body>
</html>

运行结果:

相关推荐
皮皮林5515 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河5 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
桦说编程8 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
躺平大鹅10 小时前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者11 小时前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺11 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart12 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP13 小时前
MyBatis-mybatis入门与增删改查
java
孟陬16 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端