【详解】基于Netty5.0案例NettyWebsocket

举报
皮牙子抓饭 发表于 2025/03/15 22:41:29 2025/03/15
【摘要】 基于Netty 5.0案例:NettyWebSocket随着互联网技术的不断发展,WebSocket作为一种在单个TCP连接上进行全双工通信的协议,越来越受到开发者的青睐。它允许服务端主动向客户端推送信息,非常适合实现实时数据传输的应用场景。本文将介绍如何使用Netty 5.0框架来实现一个简单的WebSocket应用。1. Netty简介Netty是一个高性能、异步事件驱动的网络应用程序框...

基于Netty 5.0案例:NettyWebSocket

随着互联网技术的不断发展,WebSocket作为一种在单个TCP连接上进行全双工通信的协议,越来越受到开发者的青睐。它允许服务端主动向客户端推送信息,非常适合实现实时数据传输的应用场景。本文将介绍如何使用Netty 5.0框架来实现一个简单的WebSocket应用。

1. Netty简介

Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。Netty极大地简化了TCP/IP和UDP/IP协议的编程工作,同时提供了高度可定制性和灵活性。

2. 准备工作

在开始之前,请确保您的开发环境中已经安装了以下工具:

  • JDK 8 或更高版本
  • Maven 3.x
  • IDE(如 IntelliJ IDEA 或 Eclipse)

3. 创建Maven项目

首先,我们需要创建一个新的Maven项目,并添加Netty 5.0的相关依赖。在​​pom.xml​​文件中添加如下依赖:

<dependencies>
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>5.0.0.Alpha2-SNAPSHOT</version>
    </dependency>
</dependencies>

注意:Netty 5.0目前处于Alpha阶段,因此可能需要从Snapshots仓库获取依赖。

4. 实现WebSocket服务器

4.1 创建WebSocket服务器初始化器

创建一个名为​​WebSocketServerInitializer​​的类,该类负责配置Netty的管道,以支持WebSocket协议。

import io.netty.channel.ChannelInitializer;
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 WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {

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

        // HTTP解码器
        pipeline.addLast(new HttpServerCodec());
        // 支持大文件传输
        pipeline.addLast(new ChunkedWriteHandler());
        // 聚合HTTP消息
        pipeline.addLast(new HttpObjectAggregator(65536));
        // WebSocket处理器
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        // 自定义处理器
        pipeline.addLast(new WebSocketFrameHandler());
    }
}

4.2 创建WebSocket帧处理器

接下来,创建一个处理WebSocket帧的处理器​​WebSocketFrameHandler​​。

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

public class WebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 接收并处理客户端发送的消息
        System.out.println("Received message: " + msg.text());

        // 向客户端发送消息
        ctx.channel().writeAndFlush(new TextWebSocketFrame("Echo: " + msg.text()));
    }

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

4.3 启动WebSocket服务器

最后,创建一个主类​​WebSocketServer​​来启动WebSocket服务器。

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 WebSocketServer {

    public static void main(String[] args) throws Exception {
        int port = 8080;

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new WebSocketServerInitializer());

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

5. 测试WebSocket服务器

启动​​WebSocketServer​​后,您可以使用浏览器或其他WebSocket客户端工具测试WebSocket连接。例如,在浏览器中打开以下URL:

ws://localhost:8080/ws

您应该能够看到服务器回显的消息。

Netty 5.0构建一个简单的WebSocket服务器。虽然Netty 5.0还处于早期阶段,但它已经展示出了强大的功能和灵活性,非常适合开发高性能的网络应用。Netty 5.0 是 Netty 的最新版本之一,虽然目前使用最广泛的还是 Netty 4.x 版本,但我们可以基于 Netty 5.0 来实现一个简单的 WebSocket 服务器。

以下是一个基于 Netty 5.0 的 WebSocket 服务器的示例代码:

1. 添加依赖

首先,在你的 ​​pom.xml​​ 文件中添加 Netty 5.0 的依赖:

<dependencies>
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>5.0.0.Alpha2</version>
    </dependency>
</dependencies>

2. 创建 WebSocket 服务器

2.1. 创建 WebSocket 服务器处理器
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;

public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {

    private WebSocketServerHandshaker handshaker;

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof FullHttpRequest) {
            handleHttpRequest(ctx, (FullHttpRequest) msg);
        } else if (msg instanceof WebSocketFrame) {
            handleWebSocketFrame(ctx, (WebSocketFrame) msg);
        }
    }

    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
        if (!req.decoderResult().isSuccess()) {
            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }

        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:8080/websocket", null, false);
        handshaker = wsFactory.newHandshaker(req);
        if (handshaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } else {
            handshaker.handshake(ctx.channel(), req);
        }
    }

    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
        if (frame instanceof TextWebSocketFrame) {
            String request = ((TextWebSocketFrame) frame).text();
            System.out.println("Received message: " + request);
            ctx.channel().writeAndFlush(new TextWebSocketFrame("Server received: " + request));
        } else if (frame instanceof CloseWebSocketFrame) {
            handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
        } else if (frame instanceof PingWebSocketFrame) {
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
        }
    }

    private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, DefaultFullHttpResponse res) {
        if (res.status().code() != 200) {
            ByteBuf buf = res.content();
            buf.writeBytes("Failure: ".getBytes(CharsetUtil.UTF_8));
            buf.writeBytes(res.status().toString().getBytes(CharsetUtil.UTF_8));
        }

        ChannelFuture f = ctx.channel().writeAndFlush(res);
        if (!isKeepAlive(req) || res.status().code() != 200) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }

    private static boolean isKeepAlive(FullHttpRequest req) {
        return HttpUtil.isKeepAlive(req);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}
2.2. 创建 WebSocket 服务器启动类
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class WebSocketServer {

    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(
                                    new HttpServerCodec(),
                                    new HttpObjectAggregator(65536),
                                    new WebSocketServerHandler()
                            );
                        }
                    });

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

3. 测试 WebSocket 服务器

你可以使用浏览器或 WebSocket 客户端工具(如 ​​websocat​​)来测试这个 WebSocket 服务器。

使用浏览器测试
  1. 打开浏览器,输入以下 URL:
ws://localhost:8080/websocket
  1. 使用 JavaScript 连接到 WebSocket 服务器并发送消息:
<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Test</title>
</head>
<body>
    <script>
        var socket = new WebSocket('ws://localhost:8080/websocket');

        socket.onopen = function() {
            console.log('Connected to WebSocket server');
            socket.send('Hello, Server!');
        };

        socket.onmessage = function(event) {
            console.log('Received from server: ' + event.data);
        };

        socket.onclose = function() {
            console.log('Disconnected from WebSocket server');
        };
    </script>
</body>
</html>

4. 运行服务器

  1. 编译并运行 ​​WebSocketServer​​ 类。
  2. 打开浏览器,访问上述 HTML 页面,你应该能看到与服务器的通信日志。

这个示例展示了如何使用 Netty 5.0 实现一个简单的 WebSocket 服务器。希望这对你有所帮助!如果有任何问题或需要进一步的帮助,请随时告诉我。当然可以!Netty 是一个高性能的异步事件驱动的网络应用框架,用于快速开发可维护的高性能协议服务器和客户端。Netty 5.0 是 Netty 的一个重要版本,虽然它并不是最新的版本(最新版本为 Netty 4.x 和 Netty 5.x 的后续版本),但其架构和设计理念仍然值得学习。

在 Netty 中实现 WebSocket 协议是一个常见的应用场景,下面将详细介绍如何使用 Netty 5.0 实现一个简单的 WebSocket 服务端。这个示例将包括服务端的启动、WebSocket 连接处理以及消息的接收和发送。

1. 添加依赖

首先,确保你的项目中包含了 Netty 的依赖。如果你使用的是 Maven,可以在 ​​pom.xml​​ 文件中添加以下依赖:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>5.0.0.Alpha2</version>
</dependency>

2. 创建 WebSocket 服务端

2.1 创建 WebSocket 服务端处理器

创建一个类 ​​WebSocketServerHandler​​ 来处理 WebSocket 连接和消息。这个类需要继承 ​​ChannelInboundHandlerAdapter​​ 并重写相关方法。

import io.netty.buffer.ByteBuf;
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
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 接收到的消息
        String request = msg.text();
        System.out.println("Service received message: " + request);

        // 发送响应消息
        String response = "Echo: " + request;
        ctx.channel().writeAndFlush(new TextWebSocketFrame(response));
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // 当有新的 WebSocket 连接时调用
        System.out.println("New WebSocket connection: " + ctx.channel().id());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // 当 WebSocket 连接断开时调用
        System.out.println("WebSocket connection closed: " + ctx.channel().id());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 处理异常
        cause.printStackTrace();
        ctx.close();
    }
}
2.2 创建 WebSocket 服务端启动类

创建一个类 ​​WebSocketServer​​ 来启动 WebSocket 服务端。

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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;
import io.netty.handler.stream.ChunkedWriteHandler;

public class WebSocketServer {

    private int port;

    public WebSocketServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        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 {
                            ch.pipeline().addLast(
                                    new HttpServerCodec(),
                                    new ChunkedWriteHandler(),
                                    new HttpObjectAggregator(65536),
                                    new WebSocketServerProtocolHandler("/ws"),
                                    new WebSocketServerHandler()
                            );
                        }
                    });

            ChannelFuture f = b.bind(port).sync();
            System.out.println("WebSocket server started at port " + port);
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new WebSocketServer(port).run();
    }
}

3. 测试 WebSocket 服务端

你可以使用浏览器或其他 WebSocket 客户端工具来测试这个 WebSocket 服务端。例如,使用浏览器的 JavaScript 控制台:

var socket = new WebSocket('ws://localhost:8080/ws');

socket.onopen = function(event) {
    console.log('Connected to WebSocket server');
    socket.send('Hello, WebSocket!');
};

socket.onmessage = function(event) {
    console.log('Received from server: ' + event.data);
};

socket.onclose = function(event) {
    console.log('Disconnected from WebSocket server');
};

4. 运行服务端

运行 ​​WebSocketServer​​ 类的 ​​main​​ 方法,启动 WebSocket 服务端。你应该会看到控制台输出服务端启动的信息。然后使用浏览器或其他客户端连接到 ​​ws://localhost:8080/ws​​,发送消息并查看响应。

总结

这个示例展示了如何处理 WebSocket 连接、接收和发送消息。你可以根据实际需求扩展这个示例,添加更多的功能和逻辑。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。