[C++]sylar高性能服务器框架学习记录:HTTPServer模块

记录一下最近这学期学习的sylar服务器框架项目,输出整理一下项目的结构,用到的知识和自己的体会

项目仓库地址

https://github.com/sylar-yin/sylar/

整理博客过程中参考的大佬资料链接:

============================================

基础介绍

该模块实现了一个HTTP服务器,继承自TcpServer并重载了handleClient方法,将accept后的socket封装成HttpSession,便于接收与发送http消息

HttpSession

HttpSession类继承自SocketStream类,封装了服务器里的http会话,提供了发送响应和接收请求的接口

// Http会话类,继承自SocketStream
class HttpSession : public SocketStream {
public:
    typedef std::shared_ptr
<HttpSession> ptr;
    HttpSession(Socket::ptr sock, bool owner = true);
    HttpRequest::ptr recvRequset();             // 接收请求报文
    int sendResponse(HttpResponse::ptr rsp);    // 发送响应报文
private:
};

HttpSession::HttpSession(Socket::ptr sock, bool owner) 
    :SocketStream(sock, owner) {
}

HttpRequest::ptr HttpSession::recvRequset() {
    // 创建解析器
    HttpRequestParser::ptr parser(new HttpRequestParser);
    // 获取缓冲区大小
    uint64_t buff_size = HttpRequestParser::GetHttpRequestBufferSize();
    // 将缓冲区交给智能指针托管
    std::shared_ptr
<char> buffer(
        new char[buff_size], [](char* ptr){
            delete[] ptr;
        });
    char* data = buffer.get();
    int offset = 0;
    // 解析工作循环
    do {
        int len = read(data + offset, buff_size - offset);
        if(len <= 0) {
            return nullptr;
        }
        len += offset;
        size_t nparse = parser->execute(data, len);
        if(parser->hasError()) {
            return nullptr;
        }
        offset = len - nparse;
        if(offset == (int)buff_size) {
            return nullptr;
        }
        if(parser->isFinished()) {
            break;
        }
    } while(true);
    // 获取body长度
    int64_t length = parser->getContentLength();
    if(length > 0) {
        std::string body;
        body.resize(length);

        int len = 0;
        if(length >= offset) {
            memcpy(&body[0], data, length);
            len = offset;
        } else {
            memcpy(&body[0], data, length);
            len = length;
        }
        length -= offset;
        if(length > 0) {
            if(readFixSize(&body[len], length) <= 0) {
                return nullptr;
            }
        }
        // 设置body
        parser->getData()->setBody(body);
    }
    std::string keep_alive = parser->getData()->getHeader("Connection");
    if(!strcmp(keep_alive.c_str(), "keep-alive")) {
        parser->getData()->setClose(false);
    }
    // 返回解析完成的request
    return parser->getData();
}

int HttpSession::sendResponse(HttpResponse::ptr rsp) {
    std::stringstream ss;
    ss << *rsp;
    std::string data = ss.str();
    return writeFixSize(data.c_str(), data.size());
}

HttpServer

// HTTP服务器类(继承自TCPServer)
class HttpServer : public TcpServer {
public:
    typedef std::shared_ptr
<HttpServer> ptr;
    HttpServer(bool keepalive = false
                , sylar::IOManager* worker = sylar::IOManager::GetThis()
                , sylar::IOManager* accept_worker = sylar::IOManager::GetThis());

    ServletDispatch::ptr getServletDispatch() const { return m_dispatch; }
    void setServletDispatch(ServletDispatch::ptr v) { m_dispatch = v; }
protected:
    virtual void handleClient(Socket::ptr client) override;
private:
    bool m_isKeepalive;                 // 是否长连接
    ServletDispatch::ptr m_dispatch;    // Servlet
};

HttpServer::HttpServer(bool keepalive, sylar::IOManager* worker, sylar::IOManager* accept_worker)
    : TcpServer(worker, accept_worker)
    , m_isKeepalive(keepalive) 
    , m_dispatch(new ServletDispatch) {
}

void HttpServer::handleClient(Socket::ptr client) {
    HttpSession::ptr session(new HttpSession(client));
    // 工作循环
    do {
        // 接收请求报文
        auto req = session->recvRequset();
        if(!req) {
            SYLAR_LOG_WARN(g_logger) << "recv http request fail, errno="
                << errno << " errstr=" << strerror(errno)
                << " client:" << *client;
            break;
        }

        // 创建响应报文
        HttpResponse::ptr rsp(new HttpResponse(req->getVersion(), req->isClose() || !m_isKeepalive));
        // 设置Header信息
        rsp->setHeader("Server", getName());
        // 执行路由函数
        m_dispatch->handle(req, rsp, session);
        // 发送响应报文
        session->sendResponse(rsp);

        // 若不支持长连接或请求关闭,退出
        if(!m_isKeepalive || req->isClose()) {
            break;
        }
    } while(true);
    // 关闭会话
    session->close();
}

测试

服务器在localhost的8020端口上监听,添加了/hello路径下的servlet路由,会返回欢迎信息

#include "sylar/http/http_server.h"
#include "sylar/log.h"

sylar::Logger::ptr g_logger = SYLAR_LOG_ROOT();

void run() {
    g_logger->setLevel(sylar::LogLevel::INFO);
    sylar::Address::ptr addr = sylar::Address::LookupAnyIPAddress("0.0.0.0:8020");
    if(!addr) {
        SYLAR_LOG_ERROR(g_logger) << "get address error";
        return;
    }

    sylar::http::HttpServer::ptr http_server(new sylar::http::HttpServer(true));
    while(!http_server->bind(addr)) {
        SYLAR_LOG_ERROR(g_logger) << "bind" << *addr << "fail";
        sleep(1);
    }

    auto sd = http_server->getServletDispatch();
    sd->addServlet("/hello", [](sylar::http::HttpRequest::ptr req
                , sylar::http::HttpResponse::ptr rsp
                , sylar::http::HttpSession::ptr session) {
        rsp->setBody("Welcome to sylar/1.0.0!");
        return 0;
    });

    http_server->start();
}

int main(int argc, char** argv) {
    sylar::IOManager iom(2);
    iom.schedule(run);
    return 0;
}

开启服务器

image-20260311005856253

使用浏览器访问,可以看到出现了欢迎信息,服务器也打印了相关日志

image-20260311010104139

image-20260311010038384

总结

封装了一个HttpServer,重载了基类的handleClient方法并声明为protected,意味着还可以继续派生

评论

  1. sankkooos
    Android Chrome 142.0.7444.173
    2 周前
    2026-3-11 18:33:04

    严肃品鉴中……

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇