为什么普通HTTP请求就像寄信,而SSE就像实时电报
想象一下:你在等待网站上新评论的通知。你每5秒刷新一次页面。服务器每次都返回一大堆HTML、CSS、图片——然后到最后,你才看到:“没有新评论”。熟悉吗?这叫做轮询(polling)。它能工作,但消耗流量并给服务器带来负担。
现在想象另一个场景:你打开一个页面,一秒钟后页面上出现一条消息:“瓦西里留下了一条评论:‘好文章!’”。无需刷新,无需额外请求。服务器自己“推送”数据给你。这就是Server-Sent Events (SSE)——一种允许服务器通过普通HTTP连接向客户端发送事件流的技术。
在本文中,我们将探讨如何在不使用重型框架的情况下,用纯C++实现SSE。您将了解为什么C++中的Server-Sent Events是监控、股票行情、聊天通知以及任何需要实时单向数据传输任务的绝佳选择。
Server-Sent Events如何工作?协议解析
SSE是HTML5规范的一部分。客户端打开一个普通的HTTP连接,并告诉服务器:“我准备好监听事件了”。服务器不会关闭连接,而是开始以特殊的text/event-stream格式发送数据。
消息格式极其简单:
data: 这是事件文本
每个事件以data:开头,以双换行符结束。可以添加id:用于标识,event:用于事件类型,以及retry:用于指定重新连接的时间(以毫秒为单位)。
一个完整流的示例:
id: 42event: new_messagedata: {"user": "瓦西里", "text": "你好!"}
id: 43event: pingdata: 服务器存活
客户端(浏览器或任何应用程序)处理这些行并生成JavaScript事件。一切巧妙之处都如此简单。
SSE vs WebSocket:何时选择哪个?
当谈到实时通信时,许多人首先想到的是WebSocket。让我们比较一下:
- WebSocket — 双向通信。客户端和服务器都可以发起交换。需要单独的协议(ws://),需要通过代理,经常被企业防火墙阻止。
- SSE — 单向通信(服务器 → 客户端)。基于普通HTTP工作。断开时自动重新连接。可以轻松通过任何代理。
如果您的任务是向客户端发送通知,而不是等待其命令,那么C++中的Server-Sent Events是一个优雅且简单的解决方案。无需引入重型库,无需编写复杂处理程序。
从零开始用C++编写SSE服务器
实现所需的最少内容:套接字和HTTP处理。在实际项目中,人们使用Boost.Beast或libmicrohttpd,但为了理解本质,我们将使用纯C++和POSIX套接字编写一个简单的服务器。
我们的服务器将:
- 接受来自客户端的HTTP请求
- 判断客户端是否需要SSE(通过
Accept: text/event-stream头) - 每2秒发送一个包含当前时间的事件流
步骤1:创建套接字并监听端口
#include <iostream>#include <string>#include <cstring>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#include <thread>#include <chrono>#include <sstream>
void handle_client(int client_socket) { // 请求缓冲区 char buffer[4096] = {0}; read(client_socket, buffer, 4096); // 检查是否为GET请求