Netty案例:WebSocket开发网页版聊天室

目录

1、开发流程

2、具体代码实现

2.1 添加依赖 (pom.xml)

2.2 配置文件(application.yml)

2.3 配置类读取设置

2.4 Netty服务器实现

2.5 WebSocket初始化器和处理器

2.6 Spring Boot启动类

2.7 HTML5客户端 (src/main/resources/static/chat.html)

2.8 启动与测试


1、开发流程

  1. 创建Spring Boot项目

  2. 添加Netty依赖

  3. 配置Netty端口和路径

  4. 实现Netty服务器

  5. 编写WebSocket处理器

  6. 创建HTML5客户端

  7. 启动和测试

2、具体代码实现

2.1 添加依赖 (pom.xml)


    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
    
    
        io.netty
        netty-all
        4.1.68.Final
    
    
    
    
        org.springframework.boot
        spring-boot-configuration-processor
        true
    

2.2 配置文件(application.yml)

netty:
  websocket:
    port: 8081  # Netty服务器端口
    path: /chat # WebSocket路径

2.3 配置类读取设置

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "netty.websocket")
public class NettyConfig {
    private int port;
    private String path;

    // Getters and Setters
    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}

2.4 Netty服务器实现

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class NettyServer {
    
    @Autowired
    private NettyConfig nettyConfig;
    
    @Autowired
    private WebSocketInitializer webSocketInitializer;
    
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    
    @PostConstruct
    public void start() throws InterruptedException {
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();
        
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(webSocketInitializer)
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        
        ChannelFuture future = bootstrap.bind(nettyConfig.getPort()).sync();
        System.out.println("Netty WebSocket服务器启动,端口:" + nettyConfig.getPort());
    }
    
    @PreDestroy
    public void shutdown() {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        System.out.println("Netty服务器已关闭");
    }
}

2.5 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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class WebSocketInitializer extends ChannelInitializer {

    @Autowired
    private NettyConfig nettyConfig;

    @Autowired
    WebSocketHandler webSocketHandler;
    
    @Override
    protected void initChannel(SocketChannel ch) {
        ChannelPipeline pipeline = ch.pipeline();
        
        // HTTP编解码器
        pipeline.addLast(new HttpServerCodec());
        // 支持大数据流
        pipeline.addLast(new ChunkedWriteHandler());
        // HTTP聚合器
        //post请求分三部分. request line / request header / message body
        // HttpObjectAggregator将多个信息转化成单一的request或者response对象
        pipeline.addLast(new HttpObjectAggregator(65536));
        // WebSocket协议处理器,将http协议升级为ws协议
        pipeline.addLast(new WebSocketServerProtocolHandler(nettyConfig.getPath(), null, true));
        // 自定义消息处理器
        pipeline.addLast(webSocketHandler);
    }
}
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;

@Component
@ChannelHandler.Sharable //设置通道共享
public class WebSocketHandler extends SimpleChannelInboundHandler {

    // 管理所有连接的Channel
    private static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        clients.add(ctx.channel());
        System.out.println("客户端连接: " + ctx.channel().id().asShortText());
    }
    
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        System.out.println("客户端断开: " + ctx.channel().id().asShortText());
    }
    
    //TextWebSocketFrame: websocket数据是帧的形式处理
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
        // 广播收到的消息
        String text = msg.text();
        System.out.println("收到消息: " + text);
        
        for (Channel channel : clients) {
            if (channel != ctx.channel()) {
                channel.writeAndFlush(new TextWebSocketFrame("用户" + ctx.channel().id().asShortText() + ": " + text));
            } else {
                channel.writeAndFlush(new TextWebSocketFrame("我: " + text));
            }
        }
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

2.6 Spring Boot启动类

2.7 HTML5客户端 (src/main/resources/static/chat.html)




    WebSocket聊天室
    


    

WebSocket聊天室

2.8 启动与测试

启动Spring Boot应用:

mvn spring-boot:run

访问客户端页面:http://localhost:8080/chat.html

打开多个浏览器窗口测试聊天功能

你可能感兴趣的:(12_计算机网络,websocket,网络协议,网络)