Tcl服务器socket重置后readable通道事件持续触发原因求助
问题根因与排查方案
核心触发原因
你遇到的chan event readable反复触发的核心原因是非阻塞套接字出错/对端断开时,你没有对应关闭套接字或取消事件绑定:
非阻塞模式下,当浏览器主动断开长连接(比如长连接超时、响应格式错误解析失败主动断开),套接字会一直触发readable事件,但调用gets会返回负数len,你当前代码的len<0分支无任何处理逻辑,直接return后事件依然保留,就会反复触发ReadLine调用。
具体代码问题排查点
- 首先补全
ReadLine中len<0分支的逻辑:
非阻塞模式下gets返回-1有两种情况:- 对端已断开连接:用
chan eof $sock判断,如果为真直接调用CloseSock $sock清理状态、取消可读事件、关闭套接字 - 仅输入缓冲区未收到完整行:直接return等待下一次事件即可
补充代码示例:
} else { # 处理len为负的情况 if {[chan eof $sock]} { CloseSock $sock return } return } - 对端已断开连接:用
- 修复
ReadLine里的状态修改错误:lset $sptr 0 0 2写法错误,你要将行状态从1修改为2,正确写法是lset $sptr 0 2,原写法会把第一个元素改为列表{2}而非数字2,导致后续行状态判断完全失效 - 修复
GetLexi的几个响应错误:- 响应头格式错误:
Content-Type: application/json; charset: utf-8中的冒号要改为等号,正确写法是Content-Type: application/json; charset=utf-8,格式错误会导致浏览器解析响应失败主动断开连接 - 发送完响应体后要加
chan flush $sock,你当前只在函数开头flush,修改-translation binary发送完json后没有flush,非阻塞模式下数据可能残留在内核缓冲区未发送给浏览器,导致浏览器超时断开 - 构造json的代码语法错误,生成的json格式不符合规范,浏览器解析失败会主动断开,建议改成转义正确的写法:
set lexi "\{\"lexi\":\"$img_base64\"\}"
- 响应头格式错误:
- 完善
ResetSock逻辑:重置状态的时候要清空state($sock)里之前存储的请求方法、路径等冗余数据,避免多次请求后数据累积导致逻辑判断错误 - 增加长连接超时处理:给每个套接字加超时定时器,超过一段时间没有新请求主动关闭连接,避免浏览器端静默断开导致的死循环触发事件
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

