小明在一家 AI 公司上班,他的智能助手经常要“借工具”:查数据库、读文件、抓网页。这些工具都存放在楼下的“工具坊”里——也就是 MCP 服务端。传话的方式有两种。第一种是“楼内传话管”:工具坊就开在同一栋楼里,两边用一根又短又粗的铜管接起来,纸条塞进去,结果原路递回来,又快又省事,可惜管子只有那么长,出了这栋楼就够不着了。第二种是“驻店快递员”:工具坊在城市的另一头,你只能靠快递系统下单,接单后店里派一位快递员常驻在你公司门口,一有结果就立刻敲门送到;但快递员只会单向送件,你想发新请求,还得重新走一遍快递系统。楼内铜管,就是 MCP 的 Stdio 传输;驻店快递员,就是 MCP 的 HTTP+SSE 传输。搞懂这两套机制的原理、性能差异、适用场景以及断线重连策略,你就能像小明一样,在任何项目里选对“传话方式”。
传输层是 MCP 架构的地基:选对 Stdio 与 SSE、看懂连接与重连,你才能把 Agent 的工具调用从 Demo 推向生产环境,这是 AI 应用工程师的必备基本功。
可视化演示
动态演示MCP传输层的核心机制,通过输入/处理/存储/输出四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
MCP传输层:Stdi Stdio传输方式的工作原理与 SSE传输方式与HTTP长连接 核心机制可视化 MCP传输层整体架构与关键组件
Stdio传输原理
周末,小明干脆把“工具坊”搬进自己电脑里——查本地文件、操作数据库,全是自家东西。工具坊是一个独立的程序,得靠“楼内传话管”沟通:小明启动它,它就变成了自己机器上的一个子进程。这根铜管的一端叫“标准输入”(stdin),另一端叫“标准输出”(stdout)。MCP 客户端把请求写成纸条塞进 stdin,服务端处理完再把结果从 stdout 递回来。两边约定好的“纸条格式”是 JSON-RPC 2.0:每个请求都带 id、method、params,每个响应回 id 和 result。纸条与纸条之间怎么分清边界?用换行符——一行一个 JSON 对象,好比每张纸条末尾盖一个“封口戳”。
换行分帧的实现极其简单:写消息时在 JSON 末尾加一个 \n,读消息时按行读取即可。这种设计天然支持流式处理,任何语言都能轻松解析。还有一个细节:标准错误输出(stderr)被约定为日志通道,只用来打印服务端的调试信息,不参与业务消息,相当于铜管旁边的“小铃铛”,响不响都不影响传纸条。Stdio 的生命周期与子进程绑定——进程被杀,会话随之结束;不监听端口、不走网络,外部根本摸不到这根管子,这是它安全边界简单的根本原因。
铜管方案快,但管子长度有限——Stdio 只能在同机进程之间使用。一旦工具坊搬去别的城市,小明就得换个思路请快递员了。
- 请求经 stdin 流入客户端把 JSON-RPC 请求写成一行文本,写入子进程的标准输入,相当于把纸条塞进铜管。
- 响应经 stdout 回流服务端处理好后,把响应同样写成一行,写到标准输出;客户端逐行读取。
- 换行符划定帧边界每条消息以换行符
\n结尾,读到一个换行就知道“这封纸条写完了”。
SSE传输原理
项目越来越大,小明要部署一个云端的“网页分析工具”。工具坊在城市的另一头,没法拉一根横跨城市的铜管,只能请“驻店快递员”。这套快递体系在协议层面对应的是 HTTP+SSE 传输。第一步,小明发一个 GET /sse 请求——服务端收到后并不急着结束响应,而是把响应“撑开”,变成一条持续开口的事件流,内容类型是 text/event-stream。紧接着,服务端发来一条特殊的 endpoint 事件,告诉小明:“以后要下单,请寄到 /messages/xxx 这个地址。”这就相当于快递员上门报到,并留下后续下单的地址。
之后的每次工具调用都是一次“下单”:小明向 endpoint 发一个 POST 请求,里面是 JSON-RPC 消息;服务端通常先回 202 Accepted 表示“收到了”,真正的处理结果稍后通过 SSE 事件推回。SSE 事件本身格式很简单:每个事件由若干字段组成(data、id、event 等),字段名后跟冒号和值,事件与事件之间用空行分隔。最关键的特性是单向:数据只从服务端流向客户端,客户端想在事件流里“说”点什么是不可能的,只能走独立的 POST。也正因如此,SSE 能轻松穿过防火墙、复用成熟的 HTTP 基础设施。
快递员只管送件不管收件,单向但胜在稳定——只要把“驻守管理”做好,远程协作就能放心交给它。
- GET /sse 建立事件流客户端发出普通 GET 请求,服务端以 text/event-stream 持续响应,不关闭连接。
- endpoint 事件报到服务端先用一条 SSE 事件下发回传地址,客户端后续用它发 POST。
- POST 发请求、事件流收结果每次调用工具都走一次 POST,结果由事件流单向推回。
性能特点对比
铜管和快递各有各的成本账。小明算了算:铜管传纸条,几乎零开销;快递送件,每单都有包装费、路程费和签收时间。落实到协议上,Stdio 走的是本地进程间通信:没有 TCP 三次握手、没有 HTTP 头、没有网络路由,每条消息只需要一个换行符做边界,延迟通常在微秒到亚毫秒级。SSE 则不同:每发一个 POST 请求,都要经历完整的 HTTP 往返,再加上服务端的 202 响应和后续事件推送,单次调用延迟比本地管道高出几个数量级;长连接还需要持续占用一个连接资源,并时刻受代理网关超时策略的约束。
性能不只有延迟这一个维度。吞吐方面,Stdio 处理大量小消息时优势明显;SSE 受限于 HTTP 栈和网络带宽,事件越密集,协议开销占比越高。资源占用方面,Stdio 每次拉起子进程都有启动成本,不适合频繁创建销毁;SSE 长连接省了握手,但服务端要为每个客户端维护连接状态,多客户端并发时占用大量文件描述符和内存。安全边界也是一个隐性差异:Stdio 不暴露端口,天然屏蔽外部访问;SSE 是网络服务,必须考虑鉴权、限流和 TLS 加密。
想追求极致速度和消息密集场景,就选楼内铜管;跨城协作的“运费”绕不开,但可以用合理的设计把开销摊薄。
- 本地 IPC 延迟同一台机器上进程间通信的延迟,量级在微秒到亚毫秒。
- TCP 三次握手SSE 每次建立或恢复连接都要先完成握手,耗时约一个半网络往返。
- HTTP 往返与网络传播请求头、响应头、代理转发、路由等待逐一叠加,把延迟放大到毫秒级以上。
适用场景判断
选铜管还是快递员,小明总结出一条经验:先看店铺开在哪里、有多少人要上门,再定传话方式。选 Stdio 的三个条件可以归纳为“同机、单客户端、无网络需求”:服务端能以子进程形式被拉起(比如一个包装了 CLI 或本地数据库的脚本)、只有当前 Agent 一个人用、不需要对外暴露服务。典型场景包括本地开发调试、私有工具接入、离线环境运行。只要有一条不满足——服务端在另一台机器上、多个 Agent 都要连、或者要让非本机进程访问——就该果断选 SSE。
SSE 的典型场景也很清晰:云端托管的工具网关,多个客户端共享一个服务实例;服务端需要主动推送进度或事件(SSE 的单向推送是天然优势);客户端环境只允许 HTTP 出站流量,比如浏览器或受限容器。真实系统里两种方式还可以混用:本地起一个 Stdio 网关进程,由它把请求转发给远程的 SSE 服务,相当于“楼内设个收发室,外面的事交给快递员”。这样既保住了本地的低延迟,又打通了跨网络的远程工具链。
位置和人数决定了协作方式;条件一旦变了,传话方式也要跟着换,这就是架构师的直觉。
- Stdio 的三个条件同机、单客户端、无需联网,三者同时满足才选管道。
- SSE 的触发条件跨机、多客户端、需要服务端推送,任何一个成立就走 HTTP。
- 混合中转本地网关聚合多个远程服务,对外统一暴露 Stdio,对内转发到 SSE。
SSE连接管理
快递员驻守期间,小明最怕两件事:小区保安把快递员当成可疑人员赶走(代理超时掐线),或者快递员送错件、丢件没法追踪。所以驻守管理要有规矩。第一件事是“报平安”:HTTP 长连接挂在代理网关(Nginx、Kong 等)后面时,网关通常有一个空闲超时,比如 60 秒没有任何数据传输就强制断开。为了让连接不“假死”,服务端要周期性发送心跳——SSE 规范里的注释行(以冒号开头)是最轻量的保活方式,客户端解析事件流时会自动忽略它,不会污染业务数据。
第二件事是消息追踪:服务端为每条 SSE 事件分配递增的 id 字段,客户端记录最后收到的 id,一旦断线就知道该从哪条消息之后续传,避免漏收。第三件事是生命周期管理:连接建立后先完成 initialize 握手,服务端记录会话状态;会话结束时,服务端发送事件或直接关闭流,客户端收到后应当停止重连;主动关闭时客户端也应通知服务端释放资源,防止连接泄漏。保活间隔有一个经验值:取“网关超时的一半”——网关 60 秒超时,就每 30 秒发一个心跳,这样既不会惊扰网关,又留足了余量。
快递员定期按门铃报平安,每件包裹都编号登记,失联也有据可查——这就是连接管理的全部艺术。
- 网关超时阈值代理网关设定空闲超时,比如 60 秒无数据就判定连接死亡并强制断开。
- 心跳周期留余量心跳间隔取超时的一半,保证“最后一声平安”离门槛足够远。
- 事件序号追踪客户端记录最后收到的事件 id,断线后据此判断从哪条消息续传。
断线重连策略
天下没有不堵车的城市,快递员也可能被堵在半路、手机没电、彻底失联。小明不能干等,他需要一套“催单策略”。客户端通常通过 EventSource 的 onerror 事件或流读取异常感知断线。最朴素的做法是立刻重连,但立刻重连往往撞上网络抖动的高峰,所有客户端一起重试还会形成“重连风暴”。成熟的策略是指数退避:第一次等 0.5 秒,第二次等 1 秒,第三次等 2 秒……每次翻倍,直到一个上限(如 30 秒),并加上随机抖动,让大家的重试时间错开。SSE 协议甚至内置了 retry 字段,服务端可以主动告诉客户端“断线后请等多少毫秒再重连”。
重连成功不等于会话恢复。SSE 事件流重新建立后,客户端必须再次完成 initialize 握手;如果服务端支持会话关联,可以通过会话标识恢复部分上下文,但 sessions 可能已被超时回收,此时客户端要能从头重建整个会话。消息层面还要做幂等:已经发出但没收到响应的请求,重发时必须保持同一个 id,服务端才能据此去重,避免同一个“删除文件”的工具被执行两次。最后的兜底是整体超时——连续重试 N 次仍失败,就放弃本次连接并向上层编排上报错误。
催单要有耐心、有节奏,更要让每笔“失联的快递单”可追溯、可重发——重连策略的本质就是不确定性下的鲁棒性设计。
- 初始延迟第一次重试等 t₀ = 0.5 秒,给网络一点喘息时间。
- 指数增长每次失败,等待时间乘 2,n 次失败后等待 t₀ × 2ⁿ。
- 封顶与抖动超过 30 秒不再增长;叠加随机 jitter 错开各客户端的重试时刻,防止风暴。
未来传输扩展
铜管够快但有距离,快递员能跨城但只会单向送件。小明忍不住想:能不能发明一个“双向对讲机”?既快又能远程,两边随时可以互喊。这正是 MCP 传输层的演进方向。协议从最初的 Stdio 与 HTTP+SSE,逐步演进出 Streamable HTTP 规范:它对客户端更友好、支持请求/响应与流式响应,同时保留了 SSE 事件流作为服务端推送的载体。再往后看,WebSocket 是呼声最高的新传输方式——一次握手后全双工,服务端能主动推送,客户端也能随时发消息,不再需要“POST 发送 + 事件流接收”的双通道分裂。
流式传输是另一个重点:大文件、长耗时工具的结果可以分块返回,客户端边收边渲染,而不是等全部完成才算结束。传输效率公式揭示了演进的本质:协议开销占比越低越好。WebSocket 的帧头只有 2 到 14 字节,相比 SSE 的 “data: “ 前缀、双换行和 HTTP 头,在高频小消息场景下节省的字节相当可观。未来还可能支持多路复用——一条连接上并发多个请求,进一步降低连接成本。这些演进的共同目标只有一个:让”传话”更快、更省、更双向。
“双向对讲机”的一天终会到来,但在那之前,理解铜管和快递员的底层逻辑,依然是所有传话方案的地基。
- 传输效率定义有效数据字节数占总传输字节数的比例,η 越接近 1 越高效。
- 协议开销HTTP 头、SSE 事件包装、握手消息等非业务字节,都要从总字节里扣除。
- WebSocket 低开销帧头仅 2~14 字节,效率显著高于 SSE 的事件包装。
AI 应用场景
场景一:本地私有工具接入(Stdio 场景)
阶段:工具接入与执行
解决的问题:团队内部的脚本、本地数据库通常不能暴露到网络;传统做法是写一堆 Shell 胶水代码,参数解析、错误处理全是重复劳动。用 Stdio 把脚本包装成 MCP server,Agent 通过标准输入输出直接调用,无需开端口、无需鉴权,进程退出即清理,安全边界清晰。
具体案例:数据分析师小张的 Agent 需要查询本地 ClickHouse 的报表。他写了一个 30 行的包装器,用子进程方式启动,Agent 每次用 JSON-RPC 请求查询,结果毫秒级返回,开发调试零网络成本。
场景二:云端多租户工具网关(SSE 场景)
阶段:服务部署与运维
解决的问题:工具部署在云上,多个 Agent 或团队要共享;纯 Stdio 无法跨网络。SSE 长连接配合心跳保活与指数退避重连,让 Agent 能稳定调用远程工具,并享受“服务端主动推送进度”的能力。
具体案例:某 SaaS 公司把“网页抓取+摘要”工具做成远程 MCP server,几十个 Agent 同时接入。运维配置 30 秒心跳,客户端实现 0.5 秒起步的退避重连,线上断连故障率大幅下降。
场景三:混合架构中转网关(演进方向)
阶段:架构设计
解决的问题:内部网络希望统一出口、统一鉴权,同时要访问多个远程 MCP 服务。本地网关进程用 Stdio 接住 Agent,内部转发到各个远程 SSE 端点,未来可平滑升级 WebSocket 全双工。
具体案例:一家银行在 DMZ 区部署 MCP 网关,前端对接内部 Agent(Stdio),后端对接风控模型服务(SSE),所有出站流量只走网关白名单,既保内网速度又守安全合规。
Python 演示
import jsonimport subprocessimport sysimport threadingimport timeimport urllib.requestfrom http.server import BaseHTTPRequestHandler, HTTPServer # ---------- 1. Stdio 式消息帧: 一行一个 JSON-RPC ----------def send_request(proc, method, params, req_id=1): msg = json.dumps({"jsonrpc": "2.0", "id": req_id, "method": method, "params": params}) proc.stdin.write(msg + "\n") proc.stdin.flush() return json.loads(proc.stdout.readline()) def stdio_server(): for line in sys.stdin: req = json.loads(line) reply = {"jsonrpc": "2.0", "id": req["id"], "result": {"city": req["params"]["city"], "weather": "sunny"}} sys.stdout.write(json.dumps(reply) + "\n") sys.stdout.flush() # ---------- 2. SSE 服务端: 每隔 0.5 秒推一条事件 ----------class SSEHandler(BaseHTTPRequestHandler): def do_GET(self): if self.path != "/sse": self.send_error(404) return self.send_response(200) self.send_header("Content-Type", "text/event-stream") self.end_headers() for i in range(5): payload = "data: " + json.dumps({"seq": i, "status": "done"}) + "\n\n" self.wfile.write(payload.encode()) self.wfile.flush() time.sleep(0.5) def log_message(self, *args): pass def start_sse_server(): server = HTTPServer(("127.0.0.1", 8765), SSEHandler) threading.Thread(target=server.serve_forever, daemon=True).start() return server # ---------- 3. SSE 客户端: 带指数退避的重连 ----------def read_sse(url, max_tries=5): delay = 0.5 for attempt in range(max_tries): try: resp = urllib.request.urlopen(url, timeout=3) print("[attempt %d] connected" % (attempt + 1)) events = [] for raw in resp: line = raw.decode().strip() if line.startswith("data:"): event = json.loads(line[5:]) events.append(event) print("got:", event) return events except Exception as exc: print("disconnected(%s), retry in %.1fs" % (exc, delay)) time.sleep(delay) delay = min(delay * 2, 8) return [] if __name__ == "__main__": if sys.argv[-1] == "server": stdio_server() else: proc = subprocess.Popen([sys.executable, __file__, "server"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) print("Stdio result:", send_request(proc, "get_weather", {"city": "Hangzhou"})) start_sse_server() read_sse("http://127.0.0.1:8765/sse") proc.terminate()
proc.stdin.write(msg + "\n")把 JSON-RPC 消息加上换行符写入子进程的标准输入,这个换行符就是“帧边界”。return json.loads(proc.stdout.readline())从标准输出逐行读取响应并解析,一行对应一帧。self.send_header("Content-Type", "text/event-stream")声明 SSE 类型,告诉客户端这是一个持续事件流而不是普通 JSON 响应。payload = "data: " + json.dumps({"seq": i, "status": "done"}) + "\n\n"SSE 事件由 data: 前缀与双换行组成,双换行是一条事件结束的标记。resp = urllib.request.urlopen(url, timeout=3)建立 SSE 长连接,迭代响应对象即可持续读取事件。delay = min(delay * 2, 8)指数退避的核心:每次失败等待时间翻倍,并封顶在 8 秒。proc = subprocess.Popen([sys.executable, __file__, "server"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)以子进程方式拉起服务端,并把标准输入输出接成管道,这就是 Stdio 的“铜管”。
常见误区
误区“SSE 不是也能实时收发吗?服务端推送、客户端再发消息,双向都可以,以后直接用 SSE 替代 WebSocket 就行。”
正解SSE 的英文全称是 Server-Sent Events,本质是服务端单向推送。客户端要发消息,必须另起一个独立的 HTTP POST 请求,事件流本身没有“上行”通道。方向上不对称,语义也不同:SSE 是“听广播”,WebSocket 是“打电话”。用比喻说:驻店快递员只负责从店里往你家送件,你要寄东西得自己再去一趟快递网点。需要严格双向、低延迟交互时,WebSocket 才更合适。
为何常见:平时用 EventSource 时既能“发”(其实是后台又发了一个 POST)又能“收”,容易把两条通道误当成一条双向通道。
误区“Stdio 不走网络、不开端口,外部根本访问不到,肯定安全,不用考虑鉴权。”
正解本地确实屏蔽了网络攻击面,但“不联网”不等于“不可信”。任何能启动该子进程的用户或进程,都可以读写它的 stdin/stdout;如果服务端本身有缺陷,恶意输入照样能触发危险操作。跨用户场景(比如服务运行在共享主机上)仍然需要做进程权限、文件系统权限隔离,必要时对消息内容做校验。用比喻说:铜管只保证“传得近”,不保证“传话的人可信”。
为何常见:人们习惯把“安全”等同于“不可达”,忽略了本地边界内部的威胁。
误区“只要我每秒钟发一个心跳,代理网关永远超不了时,连接肯定稳如泰山。”
正解心跳只解决“代理误杀空闲连接”的问题,弥补不了真实的网络断连;频率过高反而增加无谓的流量、CPU 和日志开销。合理做法是让心跳间隔略小于代理超时的一半(如代理 60 秒,心跳就设 25~30 秒),真正的稳定性要靠断线检测加指数退避重连来兜底。快递员每分钟狂按十次门铃只会烦扰保安,关键是他失联后有没有人补位。
为何常见:把“保活”误当成“加固”,以为频率越高效果越好,忽略了开销与收益的平衡。
误区“只要 EventSource 重新连上了,之前的状态就还在,继续发消息就行。”
正解重连成功后,客户端必须重新走 initialize 握手;服务端可能因超时回收了会话状态,此时要重建整个会话。另外,断线前发出但未确认的请求,重发时必须保持同一个 id,服务端才能据此去重——否则同一个“删除文件”的工具可能被执行两次。用比喻说:新来的快递员不认路,也不带你的历史包裹,一切都要重新交接;之前没送达的件要按原单号再发一次。
为何常见:长连接“看起来一直在”,让人误以为服务端的会话状态也不会丢。
面试题
Q1. MCP 的 Stdio 传输中,消息通过什么传递?
- A.客户端与服务端间的 TCP 长连接
- B.子进程的标准输入与标准输出← 正确答案
- C.HTTP POST 的请求与响应
- D.操作系统共享内存映射文件
答案:B。Stdio 就是“楼内传话管”:客户端以子进程方式拉起服务端,消息通过标准输入输出传递。TCP 长连接是 SSE/WebSocket 的传输基础,共享内存不是 MCP 的标准传输方式。
Q2. SSE 事件流中,一条事件结束的标记是什么?
- A.以单个换行符分隔
- B.以空行分隔每条事件← 正确答案
- C.以分号作为分隔符
- D.以响应结束标记分隔
答案:B。SSE 事件之间用空行(连续两个换行)分隔,相当于快递员每送完一件就停一下再送下一件;单个换行只是字段内部换行,不是事件边界。
Q3. 在 HTTP+SSE 传输中,客户端发送 JSON-RPC 请求的方式是?
- A.通过 GET 请求的查询参数
- B.在 SSE 事件流内写数据
- C.向 endpoint 地址发 POST← 正确答案
- D.用 WebSocket 的 send 方法
答案:C。事件流是单向的“收件通道”,客户端要发请求,必须向服务端下发的 endpoint 地址发 POST,服务端回 202 后稍后把结果沿事件流推回,这正是“下单走快递系统”的映射。
Q4. 下列哪种情况最适合选用 Stdio 传输?
- A.云端 SaaS 供多个租户共享
- B.同机包装本地 CLI 工具← 正确答案
- C.跨公网访问内网工具
- D.需要服务端主动推送消息
答案:B。选 Stdio 的条件是“同机、单客户端、无需网络”,本地包装 CLI 正是典型场景;云端共享、跨公网、需要推送都属于 SSE 的适用范围。
Q5. 关于 SSE 长连接管理,正确的做法包括?
- A.服务端定时发注释事件做心跳← 正确答案
- B.心跳间隔越小连接一定越稳
- C.服务端给事件分配递增的 id← 正确答案
- D.连接断开后客户端立即放弃
答案:AC。心跳可以用 SSE 注释行实现,事件 id 用于追踪与续传;但心跳间隔并非越小越好,断开后也不能直接放弃——重连策略才是稳定性的关键。
Q6. SSE 事件流使用的 MIME 类型是?
- A.用 application/json 编码
- B.用 text/plain 编码
- C.用 text/event-stream 编码← 正确答案
- D.用 text/html 编码
答案:C。SSE 的 MIME 类型是 text/event-stream,这是客户端识别“持续事件流”的依据;普通 JSON 或纯文本都不是流式事件协议。
Q7. 指数退避重连策略中,退避时间序列通常是?
- A.间隔保持恒定不变
- B.0.5s 后逐次翻倍← 正确答案
- C.间隔逐次递减加快
- D.仅在初始时重试一次
答案:B。指数退避的节奏是 0.5s、1s、2s、4s……逐次翻倍直到封顶,常加随机抖动防止重连风暴;恒定间隔或递减都不符合退避原则。
Q8. 关于“断线重连后会话恢复”,下列说法正确的是?
- A.重连后须重新 initialize 握手← 正确答案
- B.服务端用 session id 关联状态← 正确答案
- C.重发的请求可随意更换 id
- D.sessions 回收后需重建会话← 正确答案
答案:ABD。重连后需重新 initialize,会话可能已因超时被回收,此时要重建;服务端用 session id 关联历史状态,重发的请求保持同一 id 才能幂等去重,随意更换 id 会导致重复执行。
Q9. 假设代理网关 60 秒无数据就断开连接,最合理的心跳间隔是?
- A.每秒一次心跳
- B.每 10 秒一次心跳← 正确答案
- C.每 55 秒一次心跳
- D.每 90 秒一次心跳
答案:B。安全的心跳间隔应不超过网关超时的一半,即 30 秒;10 秒稳妥且开销可接受。55 秒太贴近阈值,90 秒必然超时被掐断,1 秒又过于频繁。
Q10. 下列关于 MCP 传输层未来演进的说法,正确的是?
- A.WebSocket 提供全双工通信能力← 正确答案
- B.流式传输把工具结果分块返回← 正确答案
- C.Streamable HTTP 沿用 SSE 事件流← 正确答案
- D.SSE 已被彻底废弃不再使用
答案:ABC。WebSocket 全双工、流式分块传输都是明确演进方向,Streamable HTTP 仍以 SSE 事件流作为服务端推送载体;但 SSE 远未废弃,它依然是重要的服务端推送协议。