PHP客户端需先发送0x8关闭帧(如hex2bin('880203e8')),再接收服务端响应帧,最后fclose();直接fclose()或stream_socket_shutdown()均不满足RFC 6455优雅关闭要求。

PHP 客户端连接 WebSocket 后如何主动关闭?
PHP 本身没有原生 WebSocket 客户端支持,fsockopen 或 stream_socket_client 建立的是裸 TCP 连接,不带 WebSocket 协议帧解析能力。所以「关闭 WebSocket 连接」不是简单 fclose() 就完事——你得先发一个标准的 0x8 类型关闭帧(Close frame),再等对端响应,最后才断开底层 socket。
用 rludlow/websocket-client 等库时怎么调 close()?
主流 PHP WebSocket 客户端库(如 rludlow/websocket-client、textalk/websocket)都封装了关闭逻辑。关键点是:调用 close() 不等于立即断开,它会尝试发送关闭帧并等待对方回 ACK;如果超时或对方没响应,底层 socket 才强制释放。
-
close()默认带状态码1000(正常关闭),可传入自定义码如close(4001) - 部分库要求在
close()前确保已收到onOpen回调,否则可能抛WebSocketException - 若服务端未实现关闭帧处理(比如只用
ws://+netcat模拟),close()可能阻塞或静默失败
自己用 stream_socket_client 手动关,必须发关闭帧吗?
必须。RFC 6455 明确要求:任意一端想优雅关闭,必须先发送 0x8 帧,且 payload 前 2 字节为状态码(网络字节序)。跳过这步直接 fclose(),服务端会收到 connection reset 或标记为异常断连。
手动构造关闭帧示例(状态码 1000):
立即学习“PHP免费学习笔记(深入)”;
hex2bin('880203e8')
其中 03e8 是 1000 的十六进制大端表示。注意:发送后应读取服务端返回的关闭帧(最多 125 字节),再调用 fclose();否则可能丢数据或触发重连逻辑。
为什么 stream_socket_shutdown($fp, STREAM_SHUT_RDWR) 不行?
这个函数只是关闭 socket 的读写通道,不发送任何 WebSocket 协议帧。服务端收不到关闭意图,会继续等待数据,直到超时踢出连接。实际效果等同于网络中断,不属于「优雅关闭」。
真正要做的顺序只有这一条路径:发关闭帧 → 收响应帧 → 关 socket。中间任何一步缺失或超时,都意味着连接没被对方「认可式结束」。
最常被忽略的是等待响应帧这步——很多人以为发完就完了,结果服务端还在等 ACK,客户端却已关 socket,造成状态不一致。











