Netty + websocket聊天室

Netty与WebSocket实现聊天室
本文介绍了如何利用Netty和WebSocket创建聊天室。通过处理HTTP请求和WebSocket升级握手,结合Netty的ChannelGroup实现消息广播,使得可以将消息发送到多个频道。在关闭服务器时,利用ChannelGroup的特性确保有序关闭。

Netty + websocket聊天室

程序处理逻辑

图1.png

启用websocket

从标准的HTTP或者HTTPS协议切换到WebSocket时,将会使用一种称为升级握手的机制。因此,使用WebSocket的应用程序将始终以HTTP/S作为开始,然后再执行升级。这个升级动作发生的确切时刻特定于应用程序;它可能会发生在启动时,也可能会发生在请求了某个特定的URL之后

约定:

  • 如果被请求的 URL 以/ws 结尾,那么我们将会把该协议升级为 WebSocket;

  • 否则,服务器将使用基本的 HTTP/S

服务器逻辑:

图2.png

处理http请求以及websocket

图3.png


//扩展 SimpleChannel-InboundHandler 以处理FullHttpRequest 消息
public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private final String wsUri;
    private static final File INDEX;

    static {
        URL location = HttpRequestHandler.class.getProtectionDomain().getCodeSource().getLocation();
        try {
            String path = location.toURI() + "index.html";
            path = !path.contains("file:") ? path : path.substring(5);
            INDEX = new File(path);
        } catch (URISyntaxException e) {
            throw new IllegalStateException("Unable to locate WebsocketChatClient.html", e);
        }
    }

    public HttpRequestHandler(String wsUri) {
        this.wsUri = wsUri;
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Excep
### 构建基于NettyWebSocket聊天室 #### 创建初始项目结构 为了创建一个基于NettyWebSocket聊天室,首先需要设置项目的依赖项并初始化基本环境。这通常涉及到引入必要的库文件以及配置构建工具。 对于Maven项目,在`pom.xml`中添加如下依赖: ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.78.Final</version> </dependency> ``` #### 编写服务器启动类 定义一个入口程序来启动WebSocket服务器实例,并监听特定端口上的连接请求。 ```java public class ChatServer { private final int port; public static void main(String[] args) throws Exception { new ChatServer(8080).start(); } public ChatServer(int port){ this.port = port; } public void start() throws InterruptedException{ EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); // (2) b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // (3) .childHandler(new ChannelInitializer<SocketChannel>() { // (4) @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("/ws")); p.addLast(new TextWebSocketFrameHandler()); // 自定义处理器 } }) .option(ChannelOption.SO_BACKLOG, 128) // (5) .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) ChannelFuture f = b.bind(port).sync(); // (7) System.out.println("Websocket server started at ws://localhost:" + port); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } ``` 这段代码设置了两个线程组分别负责接收新连接(`bossGroup`)和服务已建立的会话(`workerGroup`);接着指定了使用的传输通道类型为NIO socket channel;最后通过管道机制注册了一系列编解码器与业务逻辑处理器[^1]。 #### 定义消息处理逻辑 编写自定义的消息处理器以响应来自客户端的不同类型的帧(文本或二进制),这里仅展示处理文本消息的情况。 ```java import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { String request = msg.text(); System.out.println("Received message from client: " + request); // Echo back the received message to all connected clients. broadcast(request); // Send a reply to the sender indicating receipt of their message. ctx.writeAndFlush(new TextWebSocketFrame("Message Received!")); } private synchronized void broadcast(String message){ for (ChannelHandlerContext c : channels.values()){ c.writeAndFlush(new TextWebSocketFrame(message)); } } // A map holding references to active connections so we can send messages to them later on. private Map<String, ChannelHandlerContext> channels = Collections.synchronizedMap(new HashMap<>()); @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { super.handlerAdded(ctx); channels.put(ctx.channel().id().asShortText(), ctx); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { super.handlerRemoved(ctx); channels.remove(ctx.channel().id().asShortText()); } } ``` 此部分实现了当接收到新的文本消息时向所有在线用户转发该条目,并且回应给原作者确认信息的功能[^2]。 #### 测试与验证 完成上述编码工作后即可运行ChatServer.java中的main函数开启服务进程。此时可以通过浏览器或其他支持WebSocket协议的应用尝试接入指定地址(ws://localhost:8080/ws),进而测试聊天系统的交互效果[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值