首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >从零开始实现一个C++高性能服务器框架----Servlet模块

从零开始实现一个C++高性能服务器框架----Servlet模块

作者头像
用户11754185
发布2025-12-16 18:39:50
发布2025-12-16 18:39:50
110
举报

简介

项目介绍:实现了一个基于协程的服务器框架,支持多线程、多协程协同调度;支持以异步处理的方式提高服务器性能;封装了网络相关的模块,包括socket、http、servlet等,支持快速搭建HTTP服务器或WebSokcet服务器。

详细内容:日志模块,使用宏实现流式输出,支持同步日志与异步日志、自定义日志格式、日志级别、多日志分离等功能。线程模块,封装pthread相关方法,封装常用的锁包括(信号量,读写锁,自旋锁等)。IO协程调度模块,基于ucontext_t实现非对称协程模型,以线程池的方式实现多线程,多协程协同调度,同时依赖epoll实现了事件监听机制。定时器模块,使用最小堆管理定时器,配合IO协程调度模块可以完成基于协程的定时任务调度。hook模块,将同步的系统调用封装成异步操作(accept, recv, send等),配合IO协程调度能够极大的提升服务器性能。Http模块,封装了sokcet常用方法,支持http协议解析,客户端实现连接池发送请求,服务器端实现servlet模式处理客户端请求,支持单Reator多线程,多Reator多线程模式的服务器。

Servlet模块

HTTP Servlet包括两部分,第一部分是Servlet对象,每个Servlet对象表示一种处理HTTP消息的方法,第二部分是ServletDispatch,它包含一个请求路径到Servlet对象的映射,用于指定一个请求路径该用哪个Servlet来处理。

1. 主要功能
  • 提供HTTP请求路径到处理类的映射,用于规范化的HTTP消息处理流程。
2. 功能演示
  • 一个简单的服务器,由ServletDispatch完成uri对应的逻辑处理
代码语言:javascript
复制
johnsonli::http::HttpServer::ptr server(new johnsonli::http::HttpServer(true));
johnsonli::Address::ptr addr = johnsonli::Address::LookupAnyIPAddress("0.0.0.0:8020");
while(!server->bind(addr)) {
    sleep(2);
}

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

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

server->start();
3. 模块介绍
3.1 Servlet
  • 基类,用于封装处理请求的方法
代码语言:javascript
复制
class Servlet {
public:
    typedef std::shared_ptr<Servlet> ptr;
    Servlet(const std::string& name)
        :m_name(name) {}

    virtual ~Servlet() {}

    /**
     * @brief 处理请求
     * @param[in] request HTTP请求
     * @param[in] response HTTP响应
     * @param[in] session HTTP连接
     * @return 是否处理成功
     */
    virtual int32_t handle(johnsonli::http::HttpRequest::ptr request
                , johnsonli::http::HttpResponse::ptr response
                , johnsonli::http::HttpSession::ptr session) = 0;

    const std::string& getName() const { return m_name;}

protected:
    std::string m_name;     // servlet名称
};
3.2 FunctionServlet
  • 继承Servlet,封装了一个回调函数m_cb,用于具体的逻辑处理
代码语言:javascript
复制
class FunctionServlet : public Servlet {
public:
      /// 智能指针类型定义
      typedef std::shared_ptr<FunctionServlet> ptr;
      
      /// 函数回调类型定义
      typedef std::function<int32_t (johnsonli::http::HttpRequest::ptr request
                  , johnsonli::http::HttpResponse::ptr response
                  , johnsonli::http::HttpSession::ptr session)> callback;


      /**
       * @brief 构造函数
       * @param[in] cb 回调函数
       */
      FunctionServlet(callback cb);
      virtual int32_t handle(johnsonli::http::HttpRequest::ptr request
                  , johnsonli::http::HttpResponse::ptr response
                  , johnsonli::http::HttpSession::ptr session) override;
private:
      /// 回调函数
      callback m_cb;
};
  • handle方法处理逻辑实际上是调用的m_cb回调函数
代码语言:javascript
复制
int32_t FunctionServlet::handle(johnsonli::http::HttpRequest::ptr request
           , johnsonli::http::HttpResponse::ptr response
           , johnsonli::http::HttpSession::ptr session) {
    //调用回调
    return m_cb(request, response, session);
}
3.3 NotFoundServlet
  • 对于没有uri映射的Servlet,统一使用这个进行默认处理,返回一个404页面
代码语言:javascript
复制
/**
* @brief NotFoundServlet(默认返回404)
*/
class NotFoundServlet : public Servlet 
{
public:
   typedef std::shared_ptr<NotFoundServlet> ptr;

   NotFoundServlet(const std::string& name);

   virtual int32_t handle(johnsonli::http::HttpRequest::ptr request
               , johnsonli::http::HttpResponse::ptr response
               , johnsonli::http::HttpSession::ptr session) override;

private:
   std::string m_name;
   std::string m_content;
};

int32_t NotFoundServlet::handle(johnsonli::http::HttpRequest::ptr request
               , johnsonli::http::HttpResponse::ptr response
               , johnsonli::http::HttpSession::ptr session) {
	   response->setStatus(johnsonli::http::HttpStatus::NOT_FOUND);
	   response->setHeader("Server", "sylar/1.0.0");
	   response->setHeader("Content-Type", "text/html");
	   response->setBody(m_content);
	   return 0;
}
3.4 ServletDispatch
  • 继承Servlet,用于管理所有uri到Servle的映射unordered_map<std::string, Servlet::ptr>
代码语言:javascript
复制
class ServletDispatch : public Servlet 
{
public:
     typedef std::shared_ptr<ServletDispatch> ptr;
     typedef RWMutex RWMutexType;

     ServletDispatch();

     virtual int32_t handle(johnsonli::http::HttpRequest::ptr request
                , johnsonli::http::HttpResponse::ptr response
                , johnsonli::http::HttpSession::ptr session) override;
                
    // addServlet, delServlet, addGlobServlet, delGlobServlet, ...
private:
     /// 读写互斥量
     RWMutexType m_mutex;
     /// 精准匹配servlet MAP
     /// uri(/sylar/xxx) -> servlet
     std::unordered_map<std::string, Servlet::ptr> m_datas;
     /// 模糊匹配servlet 数组
     /// uri(/sylar/*) -> servlet
     std::vector<std::pair<std::string, Servlet::ptr>> m_globs;
     /// 默认servlet,所有路径都没匹配到时使用
     Servlet::ptr m_default;       
}; 
  • handle方法,通过request的uri,找到对应的Servlet,然后执行其对应的业务逻辑处理方法handle
代码语言:javascript
复制
int32_t ServletDispatch::handle(johnsonli::http::HttpRequest::ptr request
           , johnsonli::http::HttpResponse::ptr response
           , johnsonli::http::HttpSession::ptr session)  {
    auto slt = getMatchedServlet(request->getPath());
    if(slt) {
        slt->handle(request, response, session);
    }
    return 0;
} 
  • 如何完成映射?这里有三种映射的方式,一个是精确匹配,一个是模糊匹配,如果都没有匹配到,还有一个默认的servlet处理(NotFoundServlet)。
代码语言:javascript
复制
/// 精准匹配servlet MAP
/// uri(/sylar/xxx) -> servlet
std::unordered_map<std::string, Servlet::ptr> m_datas;
/// 模糊匹配servlet 数组
/// uri(/sylar/*) -> servlet
std::vector<std::pair<std::string, Servlet::ptr>> m_globs;
/// 默认servlet,所有路径都没匹配到时使用
Servlet::ptr m_default;
  • 精确匹配优先级大于模糊匹配
代码语言:javascript
复制
 Servlet::ptr ServletDispatch::getMatchedServlet(const std::string& uri) {
    RWMutexType::ReadLock lock(m_mutex);

    //先找m_datas,优先级更高
    auto mit = m_datas.find(uri);
    if(mit != m_datas.end()) {
        return mit->second;
    }

    //再找m_globs
    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;
}
3.5 HttpServer中使用Servlet
  • 当服务器收到一个请求时,将请求给ServletDispatch,由ServletDispatch负责uri的不同处理。
代码语言:javascript
复制
class HttpServer : public TcpServer {
public:
	// ...
    ServletDispatch::ptr getServletDispatch() const { return m_dispatch;}
    void setServletDispatch(ServletDispatch::ptr v) { m_dispatch = v;}

private:
    // ...
    ServletDispatch::ptr m_dispatch;    // Servlet分发器
};
  • handleClient中的一些改变,由ServletDispatch负责uri对应的业务逻辑处理
代码语言:javascript
复制
void HttpServer::handleClient(Socket::ptr client) {
    HttpSession::ptr session(new HttpSession(client));
    do{
        auto req = session->recvRequest();
        if(!req) 
        {
            LOG_DEBUG(g_logger) << "recv http request fail, errno="
                << errno << " errstr=" << strerror(errno)
                << " cliet:" << *client << " keep_alive=" << m_isKeepalive;
            break;
        }
        HttpResponse::ptr rsp(new HttpResponse(req->getVersion()
                            ,req->isClose() || !m_isKeepalive));

        //servlet dispatch负责处理对应的请求
        m_dispatch->handle(req, rsp, session);

        session->sendResponse(rsp); 

    }while(m_isKeepalive);
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • Servlet模块
    • 1. 主要功能
    • 2. 功能演示
    • 3. 模块介绍
    • 3.1 Servlet
    • 3.2 FunctionServlet
    • 3.3 NotFoundServlet
    • 3.4 ServletDispatch
    • 3.5 HttpServer中使用Servlet
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档