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

ObjectOutputStream无报错停止工作——视频传输广播异常求助

视频传输服务器广播停止问题分析与修复方案

针对你的视频传输服务器接收正常但几次迭代后停止广播的问题,结合代码细节,核心问题集中在线程池资源耗尽、Socket输出阻塞未处理这两个关键点,以下是具体分析和修复方案:

1. 无界线程池导致资源耗尽

你使用的Executors.newCachedThreadPool()是无界线程池,每收到一帧就给每个客户端提交一个异步任务。按75ms一帧、单房间多客户端的频率计算,短时间内会创建大量线程,操作系统线程数上限被打满后,新任务无法执行,直接导致广播停止。

修复方案:
改用有界线程池,根据并发客户端数量设置合理的线程上限和任务队列:

// 替换原线程池初始化,设置核心线程数5、最大线程数20、任务队列容量100
private ExecutorService pool = new ThreadPoolExecutor(
    5,
    20,
    60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100),
    new ThreadPoolExecutor.CallerRunsPolicy() // 队列满时让调用线程执行,避免任务丢失
);

2. Socket输出阻塞未处理,线程挂起

clientObjectOutputStream.write(imageBytes)是阻塞操作:如果客户端网络卡顿、断开连接但服务器未清理,这个write()会一直阻塞,占用线程池中的线程。同时因为你用clientObjectOutputStream作为锁对象,其他针对该客户端的广播任务也会被挂起,最终线程池被耗尽,无法处理新的广播任务。

修复方案:

  • 给Socket设置写入超时,避免无限阻塞:
    在UserWithSocket构造方法中添加超时配置:
public UserWithSocket(int id, Socket userSocket) {
    super();
    this.id = id;
    this.userSocket = userSocket;
    try {
        userSocket.setSoTimeout(5000); // 设置5秒写入超时
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 增加失效客户端清理逻辑:
    在广播任务的异常捕获块中,移除失效客户端并关闭资源:
pool.submit(() -> {
    try {
        ObjectOutputStream clientObjectOutputStream = client.getClientObjectOutputStream();
        synchronized (clientObjectOutputStream) {
            clientObjectOutputStream.write(imageBytes);
            clientObjectOutputStream.flush();
        }
        System.out.println("Frame Broadcasted");
    } catch (Exception e) {
        e.printStackTrace();
        // 移除失效客户端
        videoChatRoomClients.get(roomId).remove(client);
        // 关闭关联资源
        try {
            client.getClientObjectOutputStream().close();
            client.getUserSocket().close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
});

3. 同步锁粒度优化

你用clientObjectOutputStream作为锁对象,虽然能保证单个客户端的写入顺序,但锁竞争可能随客户端数量增加而加剧。可以调整锁粒度到UserWithSocket对象本身,简化锁逻辑:

// 改为同步UserWithSocket实例
synchronized (client) {
    ObjectOutputStream oos = client.getClientObjectOutputStream();
    oos.write(imageBytes);
    oos.flush();
}

4. 发送端流状态验证

确保发送端的objectOutputVideoStream是全局唯一且持续打开的,每次发送后的flush()操作正常执行,没有被意外关闭或重置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:22:09