
Wslay优雅关闭WebSocket连接关闭握手流程与RFC 6455状态码完整指南【免费下载链接】wslayThe WebSocket library in C项目地址: https://gitcode.com/gh_mirrors/ws/wslayWebSocket 连接并不是说断就断的它有一套正式的**关闭握手Closing Handshake**流程。如果你正在使用Wslay这个轻量级的 C 语言 WebSocket 库那么掌握优雅关闭连接的方法、理解 RFC 6455 状态码的含义是写出健壮、不会泄漏资源的服务端和客户端程序的必修课。本文将面向新手用最通俗的方式带你走完 Wslay 中的关闭流程并附上一份可直接查阅的状态码对照表。为什么 WebSocket 需要优雅关闭普通的 TCP 连接可以直接断开但 WebSocket 建立在 HTTP 之上双方可能还在传输数据。如果一方突然断开另一方会收到异常关闭1006而非正常关闭无法区分网络故障和主动下线。RFC 6455 规定关闭必须由一方发送 Close 控制帧Opcode 0x8发起另一方收到后回复一个 Close 帧作为确认然后双方才真正关闭 TCP 连接。这套请求-应答过程就是关闭握手。发起方 接收方 | -------- Close 帧 ------- | | 携带状态码原因 | | ------- Close 帧 --------- | | 自动回复相同状态码 | | -------- TCP FIN --------- | | -------- TCP FIN --------- |整个过程分成三步排队 Close 帧 → 发送 Close 帧 → 确认收到对端 Close 帧后关闭 TCP。Wslay 把前三步都封装好了你只需要关心第一步。关闭帧Close Frame长什么样关闭帧是一个控制帧控制帧的 payload 最大只有 125 字节其中前 2 字节状态码16 位整数网络字节序后 0~123 字节关闭原因必须是 UTF-8 编码的文本也就是说原因文本最长 123 字节。状态码为 0 时表示不带状态码的关闭帧payload 长度为 0。Wslay 会在收到 Close 帧时自动帮你解析状态码和原因见 wslay_event.c。RFC 6455 状态码速查表一张表看懂所有含义 Wslay 在头文件 wslay.h 中定义了 RFC 6455 的全部标准状态码也是我们日常最常用的那张表状态码宏定义含义能否发送1000WSLAY_CODE_NORMAL_CLOSURE正常关闭任务完成✅1001WSLAY_CODE_GOING_AWAY服务端要下线/页面跳转✅1002WSLAY_CODE_PROTOCOL_ERROR协议错误如收到非法帧✅1003WSLAY_CODE_UNSUPPORTED_DATA收到不支持的数据类型✅1005WSLAY_CODE_NO_STATUS_RCVD未收到状态码仅接收侧❌1006WSLAY_CODE_ABNORMAL_CLOSURE连接异常断开仅接收侧❌1007WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA数据不符合格式如非法 UTF-8✅1008WSLAY_CODE_POLICY_VIOLATION违反策略✅1009WSLAY_CODE_MESSAGE_TOO_BIG消息过大✅1010WSLAY_CODE_MANDATORY_EXT缺少强制扩展✅1011WSLAY_CODE_INTERNAL_SERVER_ERROR服务端内部错误✅1015WSLAY_CODE_TLS_HANDSHAKETLS 握手失败仅接收侧❌⚠️ 注意1005、1006、1015 是保留给接收方内部使用的绝不能主动发送。另外 1004 是保留值也不允许出现在线上流量中。应用层自定义原因请使用3000~4999区间3000-3999 给库/框架4000-4999 给私有用途。Wslay 的合法性校验函数见 wslay_event.c。第一步用 wslay_event_queue_close 主动发起关闭 主动关闭是最常见的场景比如服务端收到非法数据、应用要正常下线。Wslay 提供了一个便捷函数 wslay_event_queue_closewslay_event_queue_close(ctx, 1000, (const uint8_t *)bye, 3);它做了三件关键的事源码见 wslay_event.c校验队列状态如果之前已经排过 Close 帧会返回WSLAY_ERR_NO_MORE_MSG防止重复关闭校验原因长度reason_length超过 123 字节会返回WSLAY_ERR_INVALID_ARGUMENT构造 Close 帧状态码转成网络字节序连同原因一起打包按控制帧排队。如果传status_code 0则会排队一个零长度 payload 的关闭帧不携带状态码和原因这也是 RFC 6455 允许的。 注意这个函数只是排队真正把数据写出去要靠后续调用wslay_event_send驱动Wslay 的事件模型会在可写时自动处理。第二步收到对端 Close 帧自动回包 这是 Wslay 最贴心的地方你不需要自己写回包逻辑。当wslay_event_recv解析到对端发来的 Close 帧时Wslay 会自动完成以下动作源码见 wslay_event.c解析并校验状态码如果状态码非法自动回复 1002协议错误记录对端状态码供你通过 wslay_event_get_status_code_received 查询自动排队一个回应的 Close 帧状态码与对端相同回显原因也原样带回。一旦 Close 帧被排队Wslay 会停止接收新消息read_enabled置 0并保证队列中其他待发送的消息包括 Ping/Pong都不会再发送只发 Close 帧——参见发送队列的调度逻辑 wslay_event.c。这正是优雅的体现关闭前不夹带任何多余流量。第三步判断关闭是否完成 ✅关闭握手是异步的你怎么知道可以关闭 TCP 连接了Wslay 提供了一组状态查询函数见 wslay_event.c函数返回值含义wslay_event_get_close_received返回 1 表示已收到对端 Close 帧wslay_event_get_close_sent返回 1 表示已发送 Close 帧wslay_event_get_status_code_received对端发来的状态码wslay_event_get_status_code_sent自己发送的状态码推荐的关闭判断逻辑收到 Close 帧get_close_received为 1且自己也发完了 Close 帧get_close_sent为 1→ 关闭 TCP 连接主动关闭时先wslay_event_queue_close等对端回包后再关闭 TCP如果对端迟迟不回包可以用应用层超时兜底强制关闭。当 Close 帧真正被发送出去后Wslay 会记录status_code_sent并停止写操作write_enabled置 0见 wslay_event.c这表示你的关闭帧已完整送达。新手最容易踩的 4 个坑 ️原因文本长度超限Close 帧总 payload 上限 125 字节去掉 2 字节状态码原因最多 123 字节。超过会收到WSLAY_ERR_INVALID_ARGUMENT。重复关闭Close 帧只能发一次。再次调用wslay_event_queue_close会返回WSLAY_ERR_NO_MORE_MSG这是正常现象不是 bug。发送保留状态码1005/1006/1015 不能主动发送只能通过解析对端帧或本地检测产生。原因必须是 UTF-8Wslay 会对 Close 帧和文本帧做 UTF-8 校验非法的 UTF-8 会导致自动回复 1007无效帧载荷数据见 wslay_event.c。总结优雅关闭的正确姿势 ✨用 Wslay 实现优雅关闭 WebSocket 连接核心就三步用 wslay_event_queue_close 排队 Close 帧 → 交给事件循环发送 → 用 wslay_event_get_close_received 和 wslay_event_get_close_sent 确认双方完成握手后关闭 TCP。状态码选择上常规下线用 1000出错场景按 RFC 6455 状态码速查表精确对应应用自定义原因走 3000~4999 区间就能写出符合协议、可观测性良好的 WebSocket 应用了。官方还提供了关闭相关的完整 man 文档例如 wslay_event_get_status_code_sent.rst 和 wslay_event_get_close_sent.rst需要更细的 API 说明时可以随时查阅。【免费下载链接】wslayThe WebSocket library in C项目地址: https://gitcode.com/gh_mirrors/ws/wslay创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考