HTTP SSE 实现

参考:
SSE协议
SSE技术详解:使用 HTTP 做服务端数据推送应用的技术

一句概扩

SSE可理解为:服务端和客户端建立连接之后双方均保持连接,但仅支持服务端向客户端推送数据。推送完毕之后关闭连接,无状态行。

下面是基于libhv实现的SSE

SSE server
cpp 复制代码
int Handler::sse(const HttpContextPtr& ctx) {
    // SSEvent(message) every 1s
    hv::setInterval(10000, [ctx](hv::TimerID timerID) {
        static int ncount = 0;
        if (ctx->writer->isConnected()) {
            char szTime[DATETIME_FMT_BUFLEN] = {0};
            datetime_t now = datetime_now();
            datetime_fmt(&now, szTime);
            ctx->writer->SSEvent(szTime);
            if (++ncount >= 10) {
                //hv::killTimer(timerID);
                ctx->writer->close();
                ncount = 0;
            }
        } else {
            hv::killTimer(timerID);
        }
    });
    return HTTP_STATUS_UNFINISHED;
}
SSE client
cpp 复制代码
typedef std::function<void(const std::string& sid, const std::string& sevent, const std::string& sdata, const unsigned int retry_ms)> sse_msg_cb;
HV_INLINE int sse(http_method method, const char* url, const sse_msg_cb& msg_cb, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders,const unsigned int timeout_s = -1) {
    hv::HttpClient cli;
    HttpRequest req;
    HttpResponse resp;

    req.url = url; //
    req.method = method;
    req.timeout = timeout_s; // 不超时
    if (&body != &NoBody) {
        req.body = body;
    }
    if (&headers != &DefaultHeaders) {
        req.headers = headers;
    }

    bool bstream = false;
    req.http_cb = [msg_cb, &bstream](HttpMessage* resp, http_parser_state state, const char* data, size_t size) {
        if (state == HP_HEADERS_COMPLETE) {
            if (resp->headers["Content-Type"] == "text/event-stream") {
                bstream = true;
                return 0;
            }
        }
        else if (state == HP_BODY) {
            /*binary body should check data*/
            // printf("%s", std::string(data, size).c_str());
            resp->body.append(data, size);
            if (!bstream) return 0;
            /*/n/n获取message*/
            size_t ifind = std::string::npos;
            while ((ifind = resp->body.find("\n\n")) != std::string::npos) {
                std::string msg = resp->body.substr(0, ifind + 2);
                resp->body.erase(0, ifind + 2);

                /*解析body,暂时不考虑多data
                id:xxx\n
                event:xxx\n
                data:xxx\n
                data:xxx\n
                data:xxx\n
                retry:10000\n
                */
                auto kvs = hv::splitKV(msg, '\n', ':');
                if (msg_cb && (kvs.count("id") || kvs.count("event") || kvs.count("data") || kvs.count("retry")))
                    msg_cb(kvs.count("id") ? kvs["id"] : "", kvs.count("event") ? kvs["event"] : "", kvs.count("data") ? kvs["data"] : "",
                           kvs.count("retry") ? atoi(kvs["retry"].c_str()) : 0);
            }
        }
        return 0;
    };
    return cli.send(&req, &resp);
}
测试Demo
cpp 复制代码
 sse(HTTP_GET,"http://127.0.0.1:12900/sse", [](const std::string& sid, const std::string& sevent,
  const std::string& sdata, const unsigned int retry_ms) { 
            printf("id:%s\r\nevent:%s\r\ndata:%s\r\nretry:%u\r\n\r\n",
            sid.c_str(),sevent.c_str(),sdata.c_str(),retry_ms);
        });
相关推荐
代码中介商1 小时前
HTTP 完全指南(三):Cookie、Session 与 Token 深度详解
网络·网络协议·http
协享科技1 小时前
前端 SSE 流式响应处理实践:从接收、解析到渲染
前端·人工智能·程序人生·go·ai编程·sse
.小小陈.3 小时前
应用层协议 HTTP 全解析:从基础到实战
网络·网络协议·http
Irissgwe13 小时前
五、应用层协议HTTP
linux·网络·网络协议·http·状态码·url
曾阿伦14 小时前
Python 搭建简易HTTP服务
开发语言·python·http
米丘18 小时前
浏览器 本地存储 (cookie 、sessionStorage、localStorage)
安全·http·浏览器
Irissgwe19 小时前
5-2 - HTTPS 协议原理
网络协议·http·https·非对称加密·ca·https协议原理
sugar__salt19 小时前
LLM服务HTTP接口实战:前端HTTP请求全解与项目落地
前端·网络协议·http
雪的季节20 小时前
HTTP 和 HTTPS 五大核心区别
数据库·http·https
代码中介商1 天前
HTTP 完全指南(二):缓存机制深度详解
网络协议·http·缓存