news 2026/8/22 15:09:41

无需轮询的双向通信:http_study完整实战WebSocket服务端与客户端

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无需轮询的双向通信:http_study完整实战WebSocket服务端与客户端

无需轮询的双向通信:http_study完整实战WebSocket服务端与客户端

【免费下载链接】http_studyfollow me to study http项目地址: https://gitcode.com/gh_mirrors/ht/http_study

本文带你用http_study(follow me to study http)开源项目,在 OpenResty + Nginx 环境中从零实战WebSocket 服务端与客户端:一个 Lua 服务端脚本、一个 Lua 客户端脚本、一个 Python 客户端脚本,三步跑通无需轮询的双向通信。

为什么需要 WebSocket:告别轮询 🔄

传统的 HTTP 通信是"请求-响应"模式:客户端问一句,服务器答一句。想要服务器主动推送消息?只能靠轮询(客户端每隔几秒问一次"有新消息吗?"),既浪费带宽又延迟高。

WebSocket(RFC 6455)解决的就是这个问题:

  • 客户端与服务器通过一次 HTTP 握手建立长连接
  • 连接建立后,双方都可以主动推送数据,无需反复发起请求
  • 典型场景:即时聊天、股票行情、在线协作、游戏状态同步

http_study项目正是围绕《透视 HTTP 协议》编写的学习仓库,用 Nginx/OpenResty + Lua 把每个知识点做成可运行的实验,第 38 课就是 WebSocket 实战。

环境准备:一键克隆并启动

如果本地还没有项目代码,克隆仓库:

git clone https://gitcode.com/gh_mirrors/ht/http_study

进入www/目录后,只需执行启动脚本即可拉起整套 OpenResty 环境:

cd http_study/www ./run.sh start

💡 也支持 Docker 方式:docker pull chronolaw/http_study,详见项目根目录的 docker-compose.yml 与 Dockerfile。

启动后无需手工配置任何路由——www/conf/http/servers/locations.inc中有一个非常巧妙的正则 location:

# curl 127.1/07-1 location ~ ^/([\d|\-]+) { default_type text/plain; content_by_lua_file lua/$1.lua; }

见 locations.inc:访问/38-0就会自动执行lua/38-0.lua,访问/38-1执行lua/38-1.lua。这是 http_study 最省心的设计——每个实验一个脚本,URL 即入口。

第一步:用 20 行 Lua 写一个 WebSocket 服务端 🔌

打开 38-0.lua,整个服务端核心逻辑不到 50 行:

local server = require "resty.websocket.server" local wb, err = server:new{ timeout = 5000, max_payload_len = 1024 * 64, }

OpenResty 自带的resty.websocket.server库帮我们屏蔽了握手帧的编解码细节,server:new()就完成了一次 WebSocket 握手(见 38-0.lua)。

之后就是一个while true循环不断收帧(38-0.lua):

帧类型服务端行为说明
pingwb:send_pong()心跳保活,防止连接被中间设备掐断
textwb:send_text(data..','..data)收到什么文本,就回显拼接后的文本
closewb:send_close()协商关闭连接
超时继续等待区分 timeout 错误与真实错误,避免误关连接

这个小服务端的规则很简单:你发monado,我回monado,monado。麻雀虽小,却完整覆盖了 WebSocket 的收发、心跳、关闭三大生命周期。

第二步:Lua 客户端与服务端对练 🤝

同一个 nginx worker 里,还能直接用resty.websocket.client写客户端——见 38-1.lua,流程一目了然:

local wb, err = client:new{ timeout = 5000, max_payload_len = 1024 * 64, } local uri = "ws://127.0.0.1/38-0" local ok, err = wb:connect(uri)
  1. 连接wb:connect(uri)发起握手,连接ws://127.0.0.1/38-0
  2. 心跳send_ping()后收一帧pong,打印recv pong
  3. 业务send_text("hello websocket"),收到回显hello websocket,hello websocket
  4. 收尾send_close()正常断开(见 38-1.lua)

在终端执行:

curl 127.0.0.1/38-1

预期输出:

connect ok recv pong recv: hello websocket,hello websocket

一行命令看到完整的"连接→心跳→收发消息→关闭"闭环,这就是 WebSocket 双向通信的最小演示。

第三步:Python 客户端跨语言验证 🐍

更贴近真实场景的是用独立语言写客户端。python/websocket.py 只有 20 多行:

async with websockets.connect(uri) as ws: name = 'monado' await ws.send(name) print(f'> {name}') greeting = await ws.recv() print(f'< {greeting}')

它连接同一个地址ws://127.0.0.1/38-0,发送monado并打印服务端的回显。安装依赖后运行:

pip install websockets python python/websocket.py

输出:

> monado < monado,monado

一个 Lua 服务端 + 一个 Lua 客户端 + 一个 Python 客户端,三种视角验证同一条 WebSocket 连接,非常适合理解"协议是双方共同遵守的约定"这一本质。

抓包验证:看清 WebSocket 握手过程 🔍

想亲眼看看 WebSocket 的 HTTP 升级握手吗?项目贴心地附好了现成的抓包文件 38-1.pcapng。用 Wireshark 打开,用过滤条件http.request.method == "GET" && websocket即可定位握手请求。

握手阶段你会看到经典的三个头:

Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: <客户端随机值>

服务器返回101 Switching Protocols后,TCP 连接从"HTTP 语义"切换为"WebSocket 帧语义",此后所有数据都以二进制帧传输——这就是"一次握手、双向推送"的底层原理。

配置细节:两个值得学习的小技巧 ⚙️

  1. 超时与缓冲区:resty.conf 中统一配置了lua_socket_read_timeout等 cosocket 超时与缓冲参数,避免长连接因超时设置不当而异常断开。
  2. 拒绝普通 HTTP 访问:38-0.lua 里当握手失败(即直接用 HTTP 访问/38-0)时返回444状态码直接断连,防止 WebSocket 端口被普通 HTTP 流量"打杂"。

小结:一条连接,双向世界 🚀

本文用 http_study 的 3 个脚本完成了 WebSocket 的完整实战:

角色文件关键 API
WebSocket 服务端www/lua/38-0.luaresty.websocket.server/recv_frame
Lua 客户端www/lua/38-1.luaresty.websocket.client/send_text
Python 客户端python/websocket.pywebsockets.connect/ws.recv
抓包验证wireshark/38-1.pcapngRFC 6455 升级握手

相比轮询,WebSocket 用一次握手换来了一条全双工通道:消息实时、开销更低、代码更直观。跑通这三个脚本后,你就已经掌握了 WebSocket 服务端与客户端开发的核心骨架,接下来只需把它接入聊天室、行情推送等真实业务即可。

【免费下载链接】http_studyfollow me to study http项目地址: https://gitcode.com/gh_mirrors/ht/http_study

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/22 15:03:03

3种方法精简formik-antd打包体积:按需加载与Tree Shaking完全指南

3种方法精简formik-antd打包体积&#xff1a;按需加载与Tree Shaking完全指南 【免费下载链接】formik-antd Simple declarative bindings for Ant Design and Formik. 项目地址: https://gitcode.com/gh_mirrors/fo/formik-antd formik-antd 是一个连接 Formik 表单引擎…

作者头像 李华
网站建设 2026/8/22 15:02:42

量子计算性能分析新范式:基于约束求解与智能体推理的QuantumMind框架

1. 项目概述&#xff1a;当量子计算遇上“有约束的智能体推理”最近和几个做量子算法和体系结构的朋友聊天&#xff0c;大家都有一个共同的痛点&#xff1a;面对一个理论上宣称有“量子加速”潜力的算法或电路设计&#xff0c;我们如何能快速、可靠地评估它到底能跑多快&#x…

作者头像 李华