前言
tiger
是基于C++ 11
标准编写, 用于构建可扩展的分布式服务框架。整体设计思路清晰,理解成本低。不管是作为服务器的入门学习还是商业服务器的构建,tiger
都是一个不错的选择。
GitHub
配置系统
使用配置前需要先声明,即约定优于配置,如果没有提前声明配置不会解析对应字段
- 支持
std
基本数据类型std::string
,std::vector
,std::list
,std::set
,set::unordered_set
,std::map
,std::unordered_map
- 支持自定义类型(需要自己写对应的偏特化模板)
日志系统
- 支持标准控制台输出
- 支持文件输出
- 支持格式自定义
标识 说明 标识 说明 标识 说明 m 消息 p 日志级别 r 累计毫秒数 c 日志名称 t 线程id n 换行 d 时间 f 文件名 l 行号 T Tab F 协程id N 线程名称
线程系统
基于pthread
封装,线程类构造之后线程即开始运行,构造函数在线程真正开始运行之后才返回。使用了范围锁来实现互斥(即构造函数来加锁,析构函数来释放锁),这种方式简化锁的操作,也可以避免忘记释放锁导致的死锁问题
协程系统
基于ucontext
封装的对称协程,对外只提供yield
和resume
接口。大大降低了使用者对协程的理解和使用成本
协程调度器
对协程系统做的进一步封装,实现了一个N-M
的协程调度器,即N
个线程运行M
个协程,协程可以在线程之间进行切换,也可以绑定到指定线程运行
定时器
采用最小堆设计,基于epoll
超时实现定时器功能,精度毫秒级,支持在指定超时时间结束之后执行回调函数
I/O管理器
继承自协程调度器,封装了epoll
,支持为socket fd
注册读写事件回调函数。使用方便,灵活,扩展性高
Hook
hook
系统底层相关API
。hook
是控制到线程粒度的,可以自由选择是否开启。通过hook
可以让一些不具备异步功能的API
,展现出异步的功能
- 实现
sock
相关API
- 实现
sleep
系列函数
Socket
分装地址类为使用者提供统一接口,降低使用者对Linux
的网络编程相关API
和操作的理解和使用成本,从而提高开发效率
ByteArray序列化
ByteArray
二进制序列化模块,提供对二进制的常用操作
- 支持读写基础数据类型
- 支持字节序转换
- 支持序列化到文件和从文件反序列化
Stream
将文件、socket
封装成统一的接口。接口和设计的统一,便于后续的扩展和维护
TCPServer
基于Socket
类,封装了一个通用的TCPServer
的服务器类,提供简单的API
,可以快速绑定一个或多个地址,监听端口,启动服务,accept
连接,处理socket
连接等功能。降低使用者对网络编程的理解和使用成本
HTTP
采用Ragel
(有限状态机,性能媲美汇编),实现HTTP/1.1
的简单协议实现和uri
的解析。基于Reactor
网络模型实现HTTP
网络服务器
- 支持
HTTP
客户端(HTTPConnection
) - 支持
HTTP
服务端(HTTPSession
) - 支持
HTTP
连接池(HTTPConnectionPool
) - 支持
HTTPS
示例
HTTP服务
#include "tiger.h"
class Hello : public tiger::http::Servlet {
public:
int32_t handle(tiger::http::HTTPRequest::ptr request,
tiger::http::HTTPResponse::ptr response,
tiger::http::HTTPSession::ptr session) override {
response->set_body("Hello! I'm tiger!");
return 0;
}
};
class Bye : public tiger::http::Servlet {
public:
int32_t handle(tiger::http::HTTPRequest::ptr request,
tiger::http::HTTPResponse::ptr response,
tiger::http::HTTPSession::ptr session) override {
response->set_body("Bye!");
return 0;
}
};
int main() {
tiger::SingletonLoggerMgr::Instance()->add_loggers("tiger", "../conf/tiger.yml");
tiger::Thread::SetName("HTTP_SERVER");
TIGER_LOG_D(tiger::TEST_LOG) << "[http_server test start]";
auto iom = std::make_shared<tiger::IOManager>("HTTP_SERVER", true, 1);
iom->schedule([]() {
auto server = std::make_shared<tiger::http::HTTPServer>();
auto addr = tiger::IPAddress::LookupAny("0.0.0.0:8080");
auto ssl_addr = tiger::IPAddress::LookupAny("0.0.0.0:8081");
server->bind(addr, false);
server->bind(ssl_addr, true);
auto dsp = server->get_servlet_dispatch();
dsp->add_servlet("/hello", std::make_shared<Hello>());
dsp->add_servlet("/bye", std::make_shared<Bye>());
dsp->add_servlet(
"/close", [server](tiger::http::HTTPRequest::ptr request,
tiger::http::HTTPResponse::ptr response,
tiger::http::HTTPSession::ptr session) {
server->stop();
tiger::IOManager::GetThreadIOM()->stop();
return 0;
});
server->load_certificates("./tiger.crt", "./tiger.key");
server->start();
});
iom->start();
TIGER_LOG_D(tiger::TEST_LOG) << "[http_server test end]";
}
TCP服务
#include "tiger.h"
class EchoServer : public tiger::TCPServer {
public:
void handle_client(tiger::Socket::ptr client) override {
TIGER_LOG_D(tiger::TEST_LOG) << "[handle client:" << client << "]";
auto buf = std::make_shared<tiger::ByteArray>();
while (true) {
buf->clear();
std::vector<iovec> iovs;
buf->get_enable_write_buffers(iovs, 1024);
int rt = client->recv(&iovs[0], iovs.size());
if (rt == 0) {
TIGER_LOG_I(tiger::TEST_LOG) << "[has closed client:" << client << "]";
break;
} else if (rt < 0) {
TIGER_LOG_E(tiger::TEST_LOG) << "[client error"
<< " erron:" << strerror(errno) << "]";
break;
}
buf->set_position(buf->get_position() + rt);
buf->set_position(0);
const std::string &msg = buf->to_string();
TIGER_LOG_D(tiger::TEST_LOG) << "[Echo receive: " << msg << "]";
client->send(msg.c_str(), msg.size());
if (msg.find("stop") == 0) {
TIGER_LOG_I(tiger::TEST_LOG) << "[ECHO STOP]";
stop();
tiger::IOManager::GetThreadIOM()->stop();
}
}
}
};
void run() {
auto addr = tiger::Address::LookupAny("0.0.0.0:8080");
auto ech_server = std::make_shared<EchoServer>();
ech_server->bind(addr);
ech_server->start();
}
int main() {
tiger::SingletonLoggerMgr::Instance()->add_loggers("tiger", "../conf/tiger.yml");
tiger::Thread::SetName("TCPServer");
TIGER_LOG_D(tiger::TEST_LOG) << "[tcp_server test start]";
auto iom = std::make_shared<tiger::IOManager>("TCPServer", true, 1);
iom->schedule(run);
iom->start();
TIGER_LOG_D(tiger::TEST_LOG) << "[tcp_server test end]";
return 0;
}