SpringBoot与RSocket整合,实现在线聊天系统

RSocket 是一个高性能、双向通信的二进制协议,适用于实时数据流和低延迟应用场景。

我们为什么选择RSocket?

  • RSocket 提供了多种通信模式(Request-Response、Fire-and-Forget、Request-Stream 和 Channel),非常适合实时通信场景。相比之下,HTTP/REST 通常用于请求-响应模式,不适合长时间的连接或频繁的数据交换,可能导致较高的延迟和资源浪费。

  • RSocket 内置对流的支持,可以高效地处理大量并发连接和数据流,适合高并发的聊天系统。而传统的 HTTP/REST 需要为每个请求创建新的线程或连接,高并发情况下会导致资源耗尽和性能下降。

  • RSocket 是一个二进制协议,提供了更高的效率和灵活性。而HTTP/REST 使用文本格式(通常是 JSON 或 XML),增加了额外的开销,并且每个请求都需要单独的连接。

  • RSocket 的各个组件高度模块化,可以根据需要进行替换和优化。

  • RSocket 提供了内置的安全特性和可靠的消息传递机制。

  • RSocket 使用长连接,减少了连接建立和销毁的开销。

  • 相比于 HTTP/REST,RSocket 的协议更加轻量级,减少了不必要的头部信息。

哪些公司在使用RSocket?

  • Netflix 是 RSocket 的主要贡献者之一。他们使用 RSocket 来实现微服务间的高效通信,特别是在需要实时数据流和低延迟的应用程序中。

  • CERN (欧洲核子研究组织)使用 RSocket 来实现实时数据分析和监控系统。

  • Capital One 在其金融应用程序中使用 RSocket 来实现实时交易处理和通知系统。

  • PayPal 使用 RSocket 来实现实时支付处理和通知系统。

  • Uber 使用 RSocket 来实现实时位置跟踪和调度系统。

  • Intel 使用 RSocket 来实现实时数据分析和机器学习模型部署。

  • Samsung SDS 在其云服务和物联网解决方案中使用 RSocket。

代码实操

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>io.rsocket</groupId>
        <artifactId>rsocket-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-rsocket</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

实现RSocket服务端用于处理传入的消息

package com.example.chat;

import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.FluxSink;

import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Controller
publicclass ChatController {

    // 存储所有连接客户端的FluxSink实例,用于广播消息
    privatefinal ConcurrentHashMap<String, FluxSink<Message>> clients = new ConcurrentHashMap<>();

    /**
     * 处理发送消息请求
     *
     * @param message 要发送的消息对象
     * @return 返回空Mono表示操作完成
     */
    @MessageMapping("chat.sendMessage")
    public Mono<Void> sendMessage(Message message) {
        log.info("Received message: {}", message); // 记录接收到的消息
        // 将消息广播给所有已连接的客户端
        clients.values().forEach(sink -> sink.next(message));
        return Mono.empty(); // 操作完成
    }

    /**
     * 处理客户端连接请求
     *
     * @param username 客户端用户名
     * @return 返回一个Flux流,包含来自服务器和其他客户端的消息
     */
    @MessageMapping("chat.connect")
    public Flux<Message> connect(String username) {
        log.info("User connected: {}", username); // 记录用户连接事件
        // 创建一个新的Flux流,并将其存储在clients集合中
        return Flux.create(sink -> clients.put(username, sink))
                .doOnCancel(() -> { // 当客户端断开连接时执行的操作
                    log.info("User disconnected: {}", username); // 记录用户断开连接事件
                    clients.remove(username); // 从clients集合中移除该用户的sink
                })
                .mergeWith(Flux.interval(Duration.ofSeconds(1)) // 合并一个定时消息流
                        .map(tick -> new Message("Server", "Ping"))); // 发送心跳消息
    }
}

定义消息类用于传输数据

package com.example.chat;

import lombok.Data;

/**
 * 消息类,用于在客户端和服务端之间传输消息
 */
@Data
publicclass Message {
    private String sender; // 发送者名称
    private String content; // 消息内容

    public Message() {}

    public Message(String sender, String content) {
        this.sender = sender;
        this.content = content;
    }
}

配置RSocket服务器,接受来自客户端的连接

package com.example.chat.config;

import io.rsocket.transport.netty.server.TcpServerTransport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.rsocket.RSocketStrategies;
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;

@Configuration
publicclass RSocketConfig {

    /**
     * 配置RSocket消息处理器
     *
     * @param strategies RSocket策略
     * @return RSocket消息处理器实例
     */
    @Bean
    public RSocketMessageHandler rsocketMessageHandler(RSocketStrategies strategies) {
        RSocketMessageHandler handler = new RSocketMessageHandler();
        handler.setRSocketStrategies(strategies); // 设置RSocket策略
        handler.route("chat.*") // 设置路由模式
               .acceptMimeType(org.springframework.util.MimeTypeUtils.APPLICATION_JSON); // 设置支持的消息类型
        return handler;
    }

    /**
     * 配置TCP服务器传输方式
     *
     * @return TCP服务器传输实例
     */
    @Bean
    public TcpServerTransport tcpServerTransport() {
        return TcpServerTransport.create(7000); // 监听7000端口
    }
}

测试

需要先安装rsc 命令行工具。如果你本地没有这个命令工具,请到GitHub (https://github.com/making/rsc/releases) 自行安装。

第一个终端窗口A中订阅消息

rsc --request-stream tcp://localhost:7000 chat.connect -d "Alice"

第二个终端窗口B中发送消息

rsc --fire-and-forget tcp://localhost:7000 chat.sendMessage -d '{"sender":"Bob","content":"Hello Alice!"}'

查看第一个终端窗口A的结果

{"sender":"Server","content":"Ping"}
{"sender":"Bob","content":"Hello Alice!"}
{"sender":"Server","content":"Ping"}

关注我,送Java福利

/**
 * 这段代码只有Java开发者才能看得懂!
 * 关注我微信公众号之后,
 * 发送:"666",
 * 即可获得一本由Java大神一手面试经验诚意出品
 * 《Java开发者面试百宝书》Pdf电子书
 * 福利截止日期为2025年02月28日止
 * 手快有手慢没!!!
*/
System.out.println("请关注我的微信公众号:");
System.out.println("Java知识日历");
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值