记录一下最近这学期学习的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;
}
开启服务器

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

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

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

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

总结
添加Servlet模块让HttpServer更加完善




严肃夸赞高产中……