You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于http-kit与Clojure实现动态房间WebSocket应用的示例求助

用http-kit实现WebSocket动态房间列表的示例方案

我刚好有过用http-kit开发WebSocket房间功能的经验,给你分享一个可参考的实现思路和代码示例,完全基于http-kit本身的能力,不需要额外依赖:

核心思路:用原子维护房间状态

你提到的「将房间信息与通道一同保存在状态中」这个思路非常靠谱,http-kit运行在Clojure的JVM环境下,用**原子(Atom)**来维护全局房间状态是最直接且线程安全的方式。

1. 定义全局房间状态

我们可以用一个原子来存储所有房间的信息,结构大概是这样:

;; 房间状态结构:{room-id {:name "房间名称" :channels #{channel1 channel2} :online-count 2}}
(def rooms (atom {}))

2. 处理WebSocket连接与房间加入

当用户通过WebSocket连接请求加入某个房间时,我们需要更新全局状态,并把用户的通道(channel)关联到对应房间:

(defn ws-handler [request]
  (with-channel request channel
    ;; 从请求参数中获取房间ID和用户信息(这里假设前端通过query参数传递room-id)
    (let [room-id (get-in request [:params :room-id])
          room-name (get-in request [:params :room-name] (str "房间" room-id))]
      ;; 原子更新房间状态:如果房间不存在则创建,否则添加通道
      (swap! rooms update room-id
             (fn [room]
               (if room
                 (-> room
                     (update :channels conj channel)
                     (update :online-count inc))
                 {:name room-name :channels #{channel} :online-count 1})))
      
      ;; 给当前连接的客户端发送初始房间列表
      (send! channel (pr-str {:type "room-list" :data (get-room-list)}))
      
      ;; 监听通道断开事件,移除用户并更新房间状态
      (on-close channel (fn [status]
                          (swap! rooms update room-id
                                 (fn [room]
                                   (when room
                                     (let [new-channels (disj (:channels room) channel)
                                           new-count (count new-channels)]
                                       (if (zero? new-count)
                                         nil ; 房间没人了就删除
                                         (assoc room :channels new-channels :online-count new-count))))))
                          ;; 广播更新后的房间列表给所有客户端
                          (broadcast-room-list))))))

3. 实现获取房间列表的工具函数

这个函数用来提取房间的公共信息(不需要暴露通道细节):

(defn get-room-list []
  (mapv (fn [[room-id room-data]]
          {:id room-id
           :name (:name room-data)
           :online-count (:online-count room-data)})
        @rooms))

4. 实现房间列表广播功能

当房间状态变化时,给所有在线的WebSocket客户端推送最新的房间列表:

(defn broadcast-room-list []
  (let [room-list-msg (pr-str {:type "room-list" :data (get-room-list)})]
    ;; 遍历所有房间的所有通道,发送消息
    (doseq [[_ room-data] @rooms
            channel (:channels room-data)]
      (send! channel room-list-msg))))

5. 新增HTTP接口用于获取房间列表(可选)

如果需要支持非WebSocket客户端获取房间列表,可以加一个简单的HTTP接口:

(defn room-list-handler [request]
  (ring.util.response/response {:code 200 :data (get-room-list)}))

;; 路由配置示例(用compojure)
(def routes
  (routes
    (GET "/ws" [] ws-handler)
    (GET "/api/rooms" [] room-list-handler)))

额外建议

  • 可以给房间添加更多属性,比如创建时间、房间描述、是否私密等,只需要扩展状态中的room-data结构即可。
  • 如果担心全局原子的性能问题(比如超大量房间),可以考虑用更细粒度的状态管理,比如每个房间一个原子,但小型应用用全局原子完全足够。
  • 注意处理异常情况,比如用户请求加入不存在的房间时的默认逻辑,或者通道断开时的空值判断。

内容的提问来源于stack exchange,提问作者TrivialCase

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:13:41