news 2026/8/17 19:26:55

elli WebSocket 实现指南:Handover 机制让双工通信更简单的 30 分钟实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
elli WebSocket 实现指南:Handover 机制让双工通信更简单的 30 分钟实战

elli WebSocket 实现指南:Handover 机制让双工通信更简单的 30 分钟实战

【免费下载链接】elliSimple, robust and performant Erlang web server项目地址: https://gitcode.com/gh_mirrors/ell/elli

elli 是一个简单、健壮且高性能的 Erlang web server,专为 HTTP API 场景设计,但你同样可以用它轻松实现 WebSocket 服务。本文将带你用 30 分钟掌握 elli 的 Handover 机制:它能把 TCP socket 的控制权直接交给你的业务代码,让你从零搭建一个双工通信服务。无论你是 Erlang 新手还是正在选型 WebSocket 服务器方案,这份 elli WebSocket 实现指南都能帮你快速上手。

为什么用 elli 做 WebSocket 服务?🧐

先说结论:elli 本身不内置 WebSocket 协议解析,但它提供了一条极其优雅的"逃生通道"——Handover。相比 Cowboy 等重型框架,elli 的核心优势在于:

特性说明
🚀 高性能基于 acceptor 池 + 事件驱动,文档称其为 performant Erlang web server
📦 极简源码仅十几个模块,无重型依赖,学习成本低
🔌 可扩展Middleware 机制支持请求预处理与多 handler 链式路由
🎯 精准控制Handover 把连接控制权交给用户,协议实现完全自由

更关键的是,elli 的 CHANGELOG.md 明确提到:"Handover" a socket to user code, making it possible to implement WebSockets,也就是说 Handover 机制的设计初衷之一,就是为 WebSocket 这类长连接双工协议提供实现空间。

Handover 机制的核心原理:连接控制权交接 🔄

在了解实战之前,先花 2 分钟搞懂原理。elli 的请求处理流程通常是这样:连接建立 → 解析 HTTP 请求 → 调用回调函数 → 返回响应。而 Handover 机制在中间插入了一个"岔路口":

%% 位于 elli_http.erl 的 handle_request/4 case init(Req) of {ok, standard} -> %% 标准流程:读 body、执行回调、返回响应 ...; {ok, handover} -> %% Handover 流程:直接调用你的 handle/2, %% 由你的代码接管整个 socket! Req1 = Req#req{body = B1}, Response = Mod:handle(Req1, Args), Response end

这段逻辑就在 elli_http.erl。当你的回调模块在init/2中返回{ok, handover}时,elli 就不再按 HTTP 语义处理这个连接,而是把Req(其中携带了socket字段)直接交给你的handle/2函数。

💡一句话总结:Handover 就像你把方向盘交给了司机——之后车怎么开(协议怎么聊),完全由你决定。这正是实现 WebSocket 升级握手的理想切入点。

30 分钟实战:搭建基于 Handover 的 WebSocket 服务 🛠️

第一步:获取并编译 elli 源码(约 3 分钟)

首先克隆项目源码:

git clone https://gitcode.com/gh_mirrors/ell/elli cd elli make

项目使用 rebar 构建,依赖为空(deps, []),编译非常轻量。编译通过后,你可以先跑一下测试验证环境:

make eunit

其中 elli_handover_tests.erl 就是 Handover 路径的集成测试用例,稍后我们会对照它来理解代码。

第二步:从官方示例理解 Handover 触发方式(约 10 分钟)

elli 提供了一个开箱即用的示例模块 elli_example_callback_handover.erl,它展示了 Handover 的完整用法,核心逻辑分为三部分:

1. 在 init/2 中判定哪些请求走 Handover:

init(Req, _Args) -> case elli_request:path(Req) of [<<"hello">>, <<"world">>] -> {ok, handover}; %% 命中路径 → 触发 Handover _ -> ignore %% 其他路径 → 标准流程 end.

2. 在 handle/2 中接管连接,直接使用底层 socket 通信:

handle('GET', [<<"hello">>, <<"world">>], Req, _Args) -> Body = <<"Hello World!">>, Size = list_to_binary(integer_to_list(size(Body))), %% 绕过 elli 的响应封装,直接通过 socket 发送 elli_http:send_response(Req, 200, [{"Connection", "close"}, {"Content-Length", Size}], Body), {close, <<>>}; %% 返回 {close, _} 表示处理完毕后关闭连接

3. 其他请求照常走普通 HTTP 流程:

handle('GET', [<<"hello">>], Req, _Args) -> Name = elli_request:get_arg(<<"name">>, Req, <<"undefined">>), {ok, [], <<"Hello ", Name/binary>>}.

⚠️ 注意{close, <<>>}这个返回值——它告诉 elli"连接已由我处理完毕,请关闭 socket"。如果你的 WebSocket 连接要保持长连接,这里就要返回相应的长连接语义(例如持续循环接收数据),这也是从 Handover 到 WebSocket 的关键一步。

第三步:改造为真正的 WebSocket 双工通信(约 15 分钟)

现在你已经掌握了 Handover 的骨架,要让它"升级"成 WebSocket 服务,只需要做两件事:

  1. 完成 HTTP 升级握手:在handle/2中读取请求头,校验Upgrade: websocketSec-WebSocket-Key,然后向客户端返回101 Switching Protocols响应;
  2. 进入消息循环:握手成功后,用gen_tcp:recv/2循环读取客户端帧,解析 WebSocket 帧格式(FIN、opcode、mask、payload length 等),并调用gen_tcp:send/2回写数据。

由于 socket 已经握在你手里,双工通信的实现完全透明。你可以按需实现 ping/pong 心跳、分片消息、二进制帧等功能,不受 elli 框架的任何约束。

启动服务的方式与普通 elli 服务完全一致,只需把 callback 换成我们的模块:

{ok, Pid} = elli:start_link([{callback, elli_example_callback_handover}, {port, 3003}]).

参考 elli_handover_tests.erl 中的setup/0,你可以照葫芦画瓢写出自己的启动与集成测试。

进阶:Handover 与 Middleware 的搭配技巧 🧩

如果你的项目需要鉴权、压缩等横切逻辑,可以借助 elli_middleware.erl 实现多 handler 链式处理。Middleware 本身也是一个 elli handler,支持预处理与后处理,例如:

Config = [{mods, [ {elli_example_middleware, []}, %% 前置中间件 {elli_middleware_compress, []}, %% 压缩中间件 {elli_example_callback_handover, []} %% 真正的业务回调(Handover) ]}], elli:start_link([..., {callback, elli_middleware}, {callback_args, Config}]).

推荐把鉴权、日志放在前置中间件,让 Handover 回调专注于 WebSocket 协议本身,这样职责清晰、便于测试。

常见问题与避坑指南 🚧

  • 为什么我的 handover 请求没有触发?检查init/2的返回值:必须是{ok, handover}原子元组,且你的模块需要导出init/2handle/2handle_event/3三个函数(见 elli_example_callback_handover.erl)。
  • WebSocket 长连接如何保持?Handover 后 elli 默认流程已结束,你需要在自己的handle/2里维护消息循环,注意设置合适的 socket 接收超时,并实现心跳机制防掉线。
  • 性能如何保障?elli 每个连接由独立进程处理,天然契合 Erlang 的并发模型。WebSocket 长连接占用的进程资源远低于短连接风暴,配合min_acceptors参数调节 elli.erl 中的 acceptor 池大小即可。
  • 想用现成的 WebSocket 库?社区有基于 Handover 构建的 elli_websocket 扩展,你可以在 CHANGELOG 的 v1.0 说明中找到线索,再结合本文原理自行集成。

总结 ✅

通过本文的 30 分钟实战,你学会了:

  1. elli 作为Erlang web server的轻量、高性能特性;
  2. Handover 机制的本质:init/2返回{ok, handover}后,连接控制权交给用户代码;
  3. 基于 elli_example_callback_handover.erl 改造出 WebSocket 双工通信服务的完整思路;
  4. 与 Middleware 搭配以及常见坑位的规避方法。

elli 的哲学是"框架只管 HTTP,协议自由发挥"。Handover 机制就像一把万能钥匙,让 WebSocket 这类双工协议在你的 Erlang 服务中轻松落地。现在就 clone 一份源码动手试试吧,30 分钟后你也能拥有自己的 WebSocket 服务!🚀

【免费下载链接】elliSimple, robust and performant Erlang web server项目地址: https://gitcode.com/gh_mirrors/ell/elli

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

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

PingFangSC字体免费开源:绕过中文网页跨平台排版的三道坎

PingFangSC字体免费开源&#xff1a;绕过中文网页跨平台排版的三道坎 【免费下载链接】PingFangSC PingFangSC字体包文件、苹果平方字体文件&#xff0c;包含ttf和woff2格式 项目地址: https://gitcode.com/gh_mirrors/pi/PingFangSC 你有没有过这种崩溃瞬间&#xff1a…

作者头像 李华
网站建设 2026/8/17 19:25:45

Linux系统下R语言环境搭建与包管理全攻略

1. 项目概述&#xff1a;为什么要在Linux上折腾R&#xff1f;如果你是一个数据分析师、生物信息学研究员或者任何需要处理统计计算和可视化的开发者&#xff0c;那么R语言大概率是你工具箱里的常客。在Windows或macOS上&#xff0c;R的安装通常就是点几下鼠标的事&#xff0c;但…

作者头像 李华
网站建设 2026/8/17 19:22:45

呼叫中心服务商怎么选?技术能力、服务保障、合规资质3核心

呼叫中心服务商选型的核心风险&#xff0c;不在“选了不合适的”&#xff0c;而在“用功能列表做决策”——所有厂商的官网上都写着“智能路由”“通话录音”“工单管理”&#xff0c;但背后的架构深度天差地别。本文提出选型就绪度这一量化评估模型&#xff0c;将其拆解为架构…

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

AI Agent开发实战:从核心架构到OpenClaw本地部署指南

最近在技术社区里&#xff0c;关于AI Agent的讨论热度居高不下。从开发者论坛到创业分享&#xff0c;大家似乎都在探索同一个问题&#xff1a;如何让AI从被动的“工具”进化为能主动思考、规划和执行的“智能体”&#xff1f;这不仅是技术架构的升级&#xff0c;更是一种开发范…

作者头像 李华
网站建设 2026/8/17 19:21:12

Linux看B站还靠浏览器硬撑?这款开源客户端把弹幕和漫游一次补齐

Linux看B站还靠浏览器硬撑&#xff1f;这款开源客户端把弹幕和漫游一次补齐 【免费下载链接】bilibili-linux 基于哔哩哔哩官方客户端移植的Linux版本 支持漫游 项目地址: https://gitcode.com/gh_mirrors/bi/bilibili-linux 是不是也遇到过这样的时刻&#xff1a;想在L…

作者头像 李华