You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP原生Socket搭建WebSocket服务握手失败客户端连接异常问题

WebSocket握手失败问题修复方案

你遇到的连接失败问题是由多个细节不符合WebSocket协议规范导致的,可按以下步骤逐一修复:

现存问题排查

  • 响应头结束标识缺失:WebSocket握手属于HTTP升级协议,响应头所有字段结束后需要额外添加\r\n,也就是响应头末尾必须是两个连续的换行符\r\n\r\n,用来告知客户端响应头已传输完毕。
  • Sec-WebSocket-Key提取不纯净:正则匹配请求头中的key时,没有过滤掉值末尾的换行、空格符,导致生成的Sec-WebSocket-Accept值不符合要求。
  • 单次写入不完整:socket_write可能因为TCP缓冲区限制无法一次性写完所有响应数据,部分字节丢失会导致客户端识别不到完整握手响应。
  • 主循环阻塞:主逻辑中sleep(2)会阻塞连接处理,容易触发客户端超时。

修复代码

1. 修正握手函数逻辑

private function handshake($client) {
    if ($client instanceof Socket || is_resource($client)) {
        echo "== Client is Valid ==\n";
    }
    // 读取客户端发送的请求
    $read = socket_read($client, 2048);
    if ($read === false) {
        throw new Exception("Could not Read!!");
    }
    // 修正正则,提取纯净的Sec-WebSocket-Key
    if (preg_match("/Sec-WebSocket-Key:\s*(.*?)\s*\r\n/", $read, $matches)){
        // 确认sha1使用二进制输出
        $accept_key = base64_encode(hash("sha1", $matches[1]."258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
        // 响应头末尾加两个\r\n
        $response_header = "HTTP/1.1 101 Switching Protocols\r\n".
            "Upgrade: websocket\r\n".
            "Connection: Upgrade\r\n".
            "Sec-WebSocket-Accept: $accept_key\r\n\r\n";
        // 循环写入保证所有字节发送完成
        $response_len = strlen($response_header);
        $total_sent = 0;
        while ($total_sent < $response_len) {
            $bytes_sent = socket_write($client, substr($response_header, $total_sent), $response_len - $total_sent);
            if ($bytes_sent === false) {
                echo "\n====== Cannot send the handshake ==========\n";
                break;
            }
            $total_sent += $bytes_sent;
        }
        if ($total_sent == $response_len) {
            echo "\n====== handshake has been sent [". $total_sent ."bytes] ==========\n";
        }
    }
}

2. 修正主循环逻辑

移除不必要的sleep阻塞:

$running = true;
$clients = [];
while ($running) {
    if (count($clients) < 2) {
        $accept = socket_accept($this->socket);
        $this->handshake($accept);
        $clients[] = $accept;
        // 移除sleep(2),避免阻塞
        continue;
    }
    // 后续需要添加socket_select逻辑处理已连接客户端的消息收发,否则连接会因为无响应被断开
}

后续注意事项

握手成功后,所有客户端和服务端之间的通信都需要遵循WebSocket帧格式,不能直接传输纯文本,需要自行实现帧的编码、解码逻辑,否则后续收发消息时依然会出现连接断开问题。

内容的提问来源于stack exchange,提问作者obeid salem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 06:54:03