设备断开时Boost ASIO write操作挂起问题解决方案咨询
更优方案推荐
完全不需要为每个套接字分配独立线程,该方案在客户端并发量较高时会产生极高的线程调度开销,资源利用率极低,生产环境不可用。你目前已经完成同步写转异步写的改造,已经解决了单IO线程被完全阻塞的问题,仅需补充异步写超时控制逻辑即可解决剩余问题,具体实现如下:
- 为每个
GuiSession实例添加一个boost::asio::steady_timer成员,和当前套接字共用同一个io_context即可,无需额外创建IO上下文 - 每次触发
async_write调用后,立刻启动定时器,设置超时时间为业务可接受的阈值(比如你之前期望的5秒) - 若
async_write回调先触发:直接调用timer.cancel()取消定时器,正常处理后续写请求即可 - 若超时定时器先触发:直接调用对应套接字的
close()方法,此时挂起的async_write操作会立刻返回operation_aborted错误,你在错误回调中清理会话资源、拒绝后续写入即可
之前配置无效的原因说明
SO_SNDTIMEO参数仅对系统原生的同步读写调用生效,Boost ASIO的异步操作基于epoll等IO多路复用机制实现,不受该参数约束,因此配置后不会生效- 原生
SO_KEEPALIVE默认探测周期长达2小时,且默认探测次数、间隔都非常长,没有调整对应内核参数的情况下无法实现秒级断连检测,自然解决不了你的问题
单套接字独立线程方案的疑问解答
如果一定要采用该方案,不需要为每个线程单独分配boost::asio::io_context,每个线程独立执行同步write调用即可。但需要明确该方案仅适合客户端数量极少(≤20)的场景,并发量提升后线程切换开销会大幅占满CPU资源,完全不适合生产环境使用。
额外优化建议
你当前用互斥锁控制单活跃写的测试方案,可以改成会话级无锁写队列:所有写请求都dispatch到IO线程中写入会话的写队列,当前一个async_write回调完成后自动从队列取下一个消息发送,既没有线程安全问题,性能也远优于加锁方案。
如果对断连检测的准确率要求更高,可以在应用层加心跳机制:客户端定时发送心跳包,服务端超过阈值未收到心跳直接关闭套接字,比传输层检测的可控性、可靠性都高很多。
内容的提问来源于stack exchange,提问作者user1722025
相关产品推荐
相关产品推荐

