PHP服务端配置SSL后WebSocket wss连接收到二进制乱码如何解决
问题核心原因
仅为服务端监听Socket配置了SSL上下文,未对stream_socket_accept返回的客户端连接执行TLS握手操作,你直接读取的是未解密的TLS加密原始二进制数据,因此会出现乱码。
修复方案
按以下步骤调整代码即可解决:
- 客户端连接成功后,先调用
stream_socket_enable_crypto开启SSL加密层,完成握手后再读取数据 - 证书配置如果是证书、私钥分离的情况,需要补充
local_pk配置指定私钥文件路径 - 测试用自签名证书保留当前的
allow_self_signed、verify_peer配置即可
修正后的完整可运行代码
<?php // 创建SSL上下文 $context = stream_context_create(); // 合并了证书和私钥的pem文件只需要配置local_cert,如果分离则要加local_pk指定私钥路径 stream_context_set_option($context, 'ssl', 'local_cert', '../ssl/cert.pem'); // stream_context_set_option($context, 'ssl', 'local_pk', '../ssl/privkey.pem'); // 私钥分离时打开本行 stream_context_set_option($context, 'ssl', 'allow_self_signed', true); stream_context_set_option($context, 'ssl', 'verify_peer', false); // 创建监听Socket $socket = stream_socket_server( 'tcp://127.0.0.1:8888', $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context ); if (!$socket) { die("创建Socket失败: $errstr ($errno)"); } // 接受客户端连接 $cn = stream_socket_accept($socket, 99999, $name); // 关键:开启SSL加密,完成TLS握手 stream_socket_enable_crypto($cn, true, STREAM_CRYPTO_METHOD_TLS_SERVER); // 此时读取的就是解密后的正常WebSocket升级请求 $text = fread($cn, 1024); echo $text; ?>
可选优化方案
生产环境更推荐用Nginx/Apache做SSL卸载:
- 反向代理配置WSS请求转发到本地PHP的WS服务端口
- PHP服务不需要做任何SSL配置,保持原有普通WS逻辑即可,稳定性和性能更好
内容的提问来源于stack exchange,提问作者Andrei Nikolaenko
相关产品推荐
相关产品推荐

