avatar

mdo

Hello

  • 首页
  • 知识库
  • 归档
  • 标签
  • 关于
主页 websocket 握手
文章

websocket 握手

发表于 2026-06-17 更新于 2026-06- 17
作者 mdo
15~20 分钟 阅读

WebSocket 握手是客户端和服务器建立持久连接的桥梁。它利用标准的 HTTP/HTTPS 协议发起,通过 Upgrade 机制将连接从 HTTP 升级为 WebSocket,随后双方即可进行全双工实时通信。 [1, 2, 3, 4, 5]

握手流程分解

整个握手过程主要分为以下几个关键步骤:

  1. TCP 三次握手:底层先建立可靠的 TCP 连接。

  2. 客户端发送请求:客户端(通常为浏览器)发送一个特制的 HTTP/1.1 GET 请求。

  3. 服务端响应:服务端验证请求后,返回状态码为 101 Switching Protocols 的响应,标志握手成功。 [1, 2, 3]


报文结构示例

握手请求与响应包含特定的参数字段,以确保连接安全合法:

1. 客户端握手请求 (Request)

http

GET /chat HTTP/1.1
Host: ://example.com
Upgrade: websocket           # 关键:通知服务器升级协议
Connection: Upgrade          # 关键:表明连接将被升级
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== # 随机 Base64 字符串,用于服务端校验
Sec-WebSocket-Version: 13    # WebSocket 协议版本号
Origin: http://example.com

请谨慎使用此类代码。

2. 服务端握手响应 (Response)

http

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= # 通过特定算法生成的密钥
Sec-WebSocket-Version: 13

请谨慎使用此类代码。


核心校验机制:Sec-WebSocket-Key

为了防止恶意连接或非 WebSocket 客户端误访问,协议设计了密钥校验:

  • 服务端收到客户端的 Sec-WebSocket-Key 后,将其与全局唯一的魔术字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 拼接。

  • 使用 SHA-1 算法计算哈希值。

  • 将哈希值转换为 Base64 编码,并在响应头部的 Sec-WebSocket-Key 中返回给客户端。

  • 客户端收到后自行计算比对,一致则证明握手成功。 [1, 2, 3, 4, 5]

在 ThinkPHP 6 中使用 think-swoole 扩展时,框架默认内置了对 Socket.IO 协议的支持和封装。 [1]

Socket.IO 在建立连接时,会先发送一个特殊的 HTTP 握手请求(通常带有 ?transport=polling 或 ?transport=websocket 以及 EIO 版本参数)。think-swoole 已经内置了相关控制器,能自动识别并完成 Socket.IO 的双向握手协商(包括分配 sid)。 [1, 2]

为了配合前端的 socket.io-client 顺利连接,后端需要进行如下配置和事件拦截:


一、 核心配置:开启内置的 Socket.IO 处理器

打开 config/swoole.php 配置文件,找到 websocket 项。将 handler 切换为框架专门为 Socket.IO 准备的类:[1, 2, 3]

php

use think\swoole\websocket\socketio\Handler;

return [
    // ...
    'websocket' => [
        'enable'  => true,
        'handler' => Handler::class, // 核心:开启 Socket.IO 处理器
        // ... 其他配置
    ],
];

请谨慎使用此类代码。

二、 业务层:连接与鉴权

  1. 前端连接:使用 socket.io-client 连接,建议通过 query 携带 Token。

    javascript

    const socket = io("ws://127.0.0.1:7001", { query: { token: "..." } });
    

    请谨慎使用此类代码。

  2. 后端鉴权:在 app\listener\WsConnect.php 中利用 $ws->getSender() 获取 fd,并通过 app('request')->param('token') 校验。非法连接可调用 $ws->close()。 [1, 2, 3]

三、 自定义事件处理

Socket.IO 是事件驱动的。 [1]

  1. 注册事件:在 app\event.php 中配置。

    php

    'listen' => [
        'swoole.websocket.自定义事件名' => [\app\listener\OnCustomEvent::class],
    ],
    

    请谨慎使用此类代码。

  2. 监听处理:在监听器中通过 $ws->emit() 回应消息或进行广播。 [1]

四、 关键注意事项

  1. 协议版本:若握手失败(如 Transport unknown),通常是因为前端 socket.io-client 版本过高,建议尝试降级至 v2.x 或 v3.x。

  2. 多进程:若配置了 worker_num > 1,必须将 websocket.room.type 设置为 redis 以支持跨进程通信。[1, 2, 3, 4]

许可协议:  CC BY 4.0
分享

相关文章

下一篇

为命令创建专属“一键快捷键”

上一篇

Swoole 的底层特性完成 WebSocket 的握手控制、连接鉴权

最近更新

  • 完美地解决 TP3 老系统数据的平滑读取
  • thinkphp3 redis序列化和反序列化
  • Table 空间极易发生哈希冲突并溢出
  • 将监控程序直接跑在云端
  • AI 驱动型 Facebook 群组关键词监控 Chrome 浏览器插件

热门标签

API CodeGeex Gitkraken Management Manticore Premiere Sublime Swoole ThinkPHP ThinkPHP5

目录

©2026 mdo. 保留部分权利。