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

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

项目仓库地址

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

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

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

基础介绍

Servelt模块提供HTTP请求路径到处理类的映射,用于规范化HTTP消息的处理流程

Servelt模块包含两部分,第一部分是Servlet类和FunctionServelt类,每个Servelt类对象表示一种处理HTTP消息的方法;第二部分是ServeltDispatch类,包含一个请求路径到Servelt对象的映射

Servlet

作为Servlet模块所有类的基类使用,定义了handle纯虚函数,即路径匹配该Servlet对象时执行的回调函数,由后续子类各自实现

// HTTP请求路径路由类(基类)
class Servlet {
public:
    typedef std::shared_ptr
<Servlet> ptr;

    Servlet(const std::string& name)
        : m_name(name) {}
    virtual ~Servlet() {}
    // 纯虚函数,访问到该servlet时执行
    virtual int32_t handle(sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session) = 0;
    const std::string& getName() const { return m_name; }
protected:
    std::string m_name;     // servlet名称
};

FunctionServlet

继承自Servlet,重载了handle方法,成员变量存储了使用std::function包裹的handle函数类型的函数实例,当路径匹配时执行

// 函数式Servlet类(继承自Servlet)
class FunctionServlet : public Servlet {
public:
    typedef std::shared_ptr
<FunctionServlet> ptr;
    // 对应handle函数类型的function类型
    typedef std::function<int32_t (sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session)> callback;
    // 构造函数
    FunctionServlet(callback cb);
    // handle重载(内部执行callback)
    virtual int32_t handle(sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session) override;
private:
    callback m_cb;      // 回调执行函数
};

FunctionServlet::FunctionServlet(callback cb)
    :Servlet("FunctionServlet")
    ,m_cb(cb) {
}

int32_t FunctionServlet::handle(sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session) {
    return m_cb(request, response, session);
}

NotFoundServlet

请求的路径不存在时触发

// 404NotFoundServlet
class NotFoundServlet : public Servlet {
public:
    typedef std::shared_ptr
<NotFoundServlet> ptr;
    NotFoundServlet();
    virtual int32_t handle(sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session) override;
};

NotFoundServlet::NotFoundServlet()
    :Servlet("NotFoundServlet") {
}

int32_t NotFoundServlet::handle(sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session) {
    static const std::string& RSP_BODY = "
<html><head><title>404 Not Found"
        "</title></head>
<body><center><h1>404 Not Found</h1></center>"
        "
<hr><center>sylar/1.0.0</center></body></html>";

    response->setStatus(sylar::http::HttpStatus::NOT_FOUND);
    response->setHeader("server", "sylar/1.0.0");
    response->setHeader("Content-Type", "text/html");
    response->setBody(RSP_BODY);
    return 0;
}

ServletDispatch

继承自Servlet类,重载了handle方法,在handle内部做路径匹配并触发匹配的Servlet对象的callback函数

同时提供了精确和模糊两种匹配模式,可以使用通配符*来添加模糊路径匹配

成员变量使用了std::unordered_map来存储精确匹配,路径作为key,对应的Servelt智能指针作为value;使用std::vector来存储模糊匹配

// Servlet管理类,顶层servlet(继承自Servelt)
class ServletDispatch : public Servlet {
public:
    typedef std::shared_ptr
<ServletDispatch> ptr;
    typedef sylar::RWMutex RWMutexType;

    // 构造函数
    ServletDispatch();
    // 路由入口函数
    virtual int32_t handle(sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session) override;

    void addServlet(const std::string& uri, Servlet::ptr slt);                  // 添加精准Servelt(智能指针)
    void addServlet(const std::string& uri, FunctionServlet::callback cb);      // 添加精准Servelt(回调函数)
    void addGlobServlet(const std::string& uri, Servlet::ptr slt);              // 添加模糊Servelt(智能指针)
    void addGlobServlet(const std::string& uri, FunctionServlet::callback cb);  // 添加模糊Servlet(回调函数)

    void delServlet(const std::string& uri);        // 删除精准Servelt
    void delGlobServlet(const std::string& uri);    // 删除模糊Servelt

    Servlet::ptr getDefault() const { return m_default; }
    void setDefault(Servlet::ptr v) { m_default = v; }

    Servlet::ptr getServlet(const std::string& uri);        // 根据URI获取精准Servelt
    Servlet::ptr getGlobServlet(const std::string& uri);    // 根据URI获取模糊Servelt

    Servlet::ptr getMatchedServlet(const std::string& uri); // 匹配Servelt
private:
    // 读写锁
    RWMutexType m_mutex;
    // uri(/sylar/xxx) -> servlet 精确搜索
    std::unordered_map<std::string, Servlet::ptr> m_datas;
    // uri(/sylar/*) -> servlet 模糊搜索
    std::vector<std::pair<std::string, Servlet::ptr>> m_globs;
    // 默认servlet,所有路径都不匹配时使用
    Servlet::ptr m_default;
};

ServletDispatch::ServletDispatch()
    :Servlet("ServletDispatch") {
    m_default.reset(new NotFoundServlet());
}

int32_t ServletDispatch::handle(sylar::http::HttpRequest::ptr request
                         , sylar::http::HttpResponse::ptr response
                         , sylar::http::HttpSession::ptr session) {
    // 匹配Servelt
    auto slt = getMatchedServlet(request->getPath());
    // 执行匹配到的Servlet的handle函数
    if(slt) {
        slt->handle(request, response, session);
    }
    return 0;
}

void ServletDispatch::addServlet(const std::string& uri, Servlet::ptr slt) {
    RWMutexType::WriteLock lock(m_mutex);
    m_datas[uri] = slt;
}

void ServletDispatch::addServlet(const std::string& uri, FunctionServlet::callback cb) {
    RWMutexType::WriteLock lock(m_mutex);
    m_datas[uri].reset(new FunctionServlet(cb));
}

void ServletDispatch::addGlobServlet(const std::string& uri, Servlet::ptr slt) {
    RWMutexType::WriteLock lock(m_mutex);
    // 将原先的删除
    for(auto it = m_globs.begin(); it != m_globs.end(); it++)  {
        if(it->first == uri) {
            m_globs.erase(it);
            break;
        }
    }
    m_globs.push_back(std::make_pair(uri, slt));
}

void ServletDispatch::addGlobServlet(const std::string& uri, FunctionServlet::callback cb) {
    return addGlobServlet(uri, FunctionServlet::ptr(new FunctionServlet(cb)));
}

void ServletDispatch::delServlet(const std::string& uri) {
    RWMutexType::WriteLock lock(m_mutex);
    m_datas.erase(uri);
}

void ServletDispatch::delGlobServlet(const std::string& uri) {
    RWMutexType::WriteLock lock(m_mutex);
    for(auto it = m_globs.begin(); it != m_globs.end(); it++) {
        if(it->first == uri) {
            m_globs.erase(it);
            break;
        }
    }
}

Servlet::ptr ServletDispatch::getServlet(const std::string& uri) {
    RWMutexType::WriteLock lock(m_mutex);
    auto it = m_datas.find(uri);
    return it == m_datas.end() ? nullptr : it->second;
}

Servlet::ptr ServletDispatch::getGlobServlet(const std::string& uri) {
    RWMutexType::WriteLock lock(m_mutex);
    for(auto it = m_globs.begin(); it != m_globs.end(); it++) {
        if(it->first == uri) {
            return it->second;
        }
    }
    return nullptr;
}

Servlet::ptr ServletDispatch::getMatchedServlet(const std::string& uri) {
    RWMutexType::WriteLock lock(m_mutex);
    auto mit = m_datas.find(uri);
    if(mit != m_datas.end()) {
        return mit->second;
    }
    for(auto it = m_globs.begin(); it != m_globs.end(); it++) {
        if(!fnmatch(it->first.c_str(), uri.c_str(), 0)) {
            return it->second;
        }
    }
    return m_default;
}

测试

服务器监听localhost的5000端口,添加了两个精确Servlet,对应路径/sylar/xx以及/hello/world,一个模糊Servlet对应路径/sylar/*

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

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

void run() {
    sylar::http::HttpServer::ptr server(new sylar::http::HttpServer);
    sylar::Address::ptr addr = sylar::Address::LookupAnyIPAddress("0.0.0.0:5000");
    while(!server->bind(addr)) {
        sleep(2);
    }

    auto sd = server->getServletDispatch();
    sd->addServlet("/sylar/xx", [](sylar::http::HttpRequest::ptr req
                , sylar::http::HttpResponse::ptr rsp
                , sylar::http::HttpSession::ptr session) {
        rsp->setBody(req->toString());
        return 0;
    });

    sd->addGlobServlet("/sylar/*", [](sylar::http::HttpRequest::ptr req
                , sylar::http::HttpResponse::ptr rsp
                , sylar::http::HttpSession::ptr session) {
        rsp->setBody("Glob:\r\n" + req->toString());    
        return 0;
    });

    sd->addServlet("/hello/world", [](sylar::http::HttpRequest::ptr req
                , sylar::http::HttpResponse::ptr rsp
                , sylar::http::HttpSession::ptr session) {
        rsp->setBody("Welcome to sylar/1.0.0! \r\n Your Request:\r\n" + req->toString());    
        return 0;
    });

    server->start();
}

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

开启服务器

image-20260311105051660

使用浏览器访问路径/hello/world,可以看到成功返回了welcome界面

image-20260311105222664

使用浏览器访问/sylar/xx,成功返回预期页面

image-20260311105333490

使用浏览器访问sylar/not_exist,成功返回模糊匹配页面

image-20260311105434288

最后使用浏览器访问不存在路径,成功返回404页面

image-20260311105536422

总结

添加Servlet模块让HttpServer更加完善

评论

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

    严肃夸赞高产中……

发送评论 编辑评论


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