记录一下最近这学期学习的sylar服务器框架项目,输出整理一下项目的结构,用到的知识和自己的体会
项目仓库地址
https://github.com/sylar-yin/sylar/
整理博客过程中参考的大佬资料链接:
============================================
基础介绍
封装了一个TCP服务器,支持绑定多端口监听,支持分别指定用于监听的调度器和用于处理连接的调度器
默认handleClient方法会返回最简单的http1.1报文,内容是hello,子类可重载handleClient方法
class TcpServer : public std::enable_shared_from_this
<TcpServer>
, Noncopyable {
public:
typedef std::shared_ptr
<TcpServer> ptr;
TcpServer(sylar::IOManager* worker = sylar::IOManager::GetThis(),
sylar::IOManager* accept_worker = sylar::IOManager::GetThis());
virtual ~TcpServer();
virtual bool bind(sylar::Address::ptr addr); // 绑定单个地址
virtual bool bind(const std::vector<Address::ptr>& addrs, // 绑定多个地址
std::vector<Address::ptr>& fails);
virtual bool start(); // 启动
virtual void stop(); // 停止
uint64_t getRecvTimeout() const { return m_recvTimeout; }
std::string getName() const { return m_name; }
void setRecvTimeout(uint64_t v) { m_recvTimeout = v; }
void setName(const std::string& v) { m_name = v; }
bool isStop() const { return m_isStop; }
protected:
virtual void handleClient(Socket::ptr client); // 处理客户端
virtual void startAccept(Socket::ptr sock); // 开始接收连接
protected:
std::vector<Socket::ptr> m_socks; // 多监听多网卡
IOManager* m_worker; // 新连接的socket工作的调度器
IOManager* m_acceptworker; // 服务器监听socket接收连接的调度器
uint64_t m_recvTimeout; // 接收超时时间
std::string m_name; // 服务器名称
std::string m_type = "tcp"; // 服务器类型
bool m_isStop; // 服务器是否停止
};
构造/析构函数
TcpServer::TcpServer(sylar::IOManager* worker, sylar::IOManager* accept_worker)
: m_worker(worker)
, m_acceptworker(accept_worker)
, m_recvTimeout(g_tcp_server_read_timeout->getValue())
, m_name("sylar/1.0.0")
, m_isStop(true) {
}
TcpServer::~TcpServer() {
for(auto& i : m_socks) {
i->close();
}
m_socks.clear();
}
绑定监听地址
bool TcpServer::bind(sylar::Address::ptr addr) {
std::vector<Address::ptr> addrs;
std::vector<Address::ptr> fails;
addrs.push_back(addr);
return bind(addrs, fails);
}
bool TcpServer::bind(const std::vector<Address::ptr>& addrs,
std::vector<Address::ptr>& fails) {
// 遍历传入的要绑定的监听地址
for(auto& addr : addrs) {
// 创建TCPsocket
Socket::ptr sock = Socket::CreateTCP(addr);
// bind
if(!sock->bind(addr)) {
SYLAR_LOG_ERROR(g_logger) << "bind fail errno="
<< errno << " errstr=" << strerror(errno)
<< " addr=[" << addr->toString() << "]";
// 收集绑定失败的地址
fails.push_back(addr);
continue;
}
// 设置监听
if(!sock->listen()) {
SYLAR_LOG_ERROR(g_logger) << "listen fail errno="
<< errno << " errstr=" << strerror(errno)
<< " addr=[" << addr->toString() << "]";
// 收集设置监听失败的地址
fails.push_back(addr);
continue;
}
// 绑定监听完成,加入数组
m_socks.push_back(sock);
}
if(!fails.empty()) {
m_socks.clear();
return false;
}
// 若没有失败,打印日志
for(auto& i : m_socks) {
SYLAR_LOG_INFO(g_logger) << "sever bind success: " << *i;
}
return true;
}
开启/关闭服务器
bool TcpServer::start() {
if(!m_isStop) {
return true;
}
m_isStop = false;
// 调度每个监听socket的接收任务
for(auto& sock : m_socks) {
m_acceptworker->schedule(std::bind(&TcpServer::startAccept,
shared_from_this(), sock));
}
return true;
}
void TcpServer::stop() {
m_isStop = true;
auto self = shared_from_this();
// 将this和self作为参数传递给异步任务的Lambda函数,确保异步任务执行期间,当前对象的shared_ptr一直有效
m_acceptworker->schedule([this, self]() {
for(auto& sock : m_socks) {
sock->cancelAll();
sock->close();
}
m_socks.clear();
});
}
accept工作循环
void TcpServer::startAccept(Socket::ptr sock) {
// 工作循环
while(!m_isStop) {
// 调用accept(已被hook)
Socket::ptr client = sock->accept();
// 如果连接成功
if(client) {
// 打印日志
SYLAR_LOG_INFO(g_logger) << "sock=" << *client << "connected";
// 设置接收超时时间
client->setRecvTimeout(m_recvTimeout);
// 在工作调度器上为每个连接成功的socket调度handleClient
// handleClient结束之前,TCPServer不能结束
m_worker->schedule(std::bind(&TcpServer::handleClient,
shared_from_this(), client));
} else {
SYLAR_LOG_ERROR(g_logger) << "accept errno=" << errno
<< "errstr=" << strerror(errno);
}
}
}
handleClient方法
默认发回hello报文
void TcpServer::handleClient(Socket::ptr client) {
SYLAR_LOG_INFO(g_logger) << "handle client: " << *client;
const char* rsp =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 5\r\n"
"\r\n"
"hello";
client->send(rsp, strlen(rsp));
}
测试
监听localhost的8033端口
#include "sylar/tcp_server.h"
#include "sylar/iomanager.h"
#include "sylar/log.h"
static sylar::Logger::ptr g_logger = SYLAR_LOG_ROOT();
void run() {
auto addr = sylar::Address::LookupAny("0.0.0.0:8033");
// auto addr2 = sylar::UnixAddress::ptr(new sylar::UnixAddress("/tmp/unix_addr"));
std::vector<sylar::Address::ptr> addrs;
addrs.push_back(addr);
// addrs.push_back(addr2);
sylar::TcpServer::ptr tcp_server(new sylar::TcpServer);
std::vector<sylar::Address::ptr> fails;
// ::unlink("/tmp/unix_addr");
while(!tcp_server->bind(addrs, fails)) {
sleep(2);
}
tcp_server->start();
}
int main(int argc, char** argv) {
sylar::IOManager iom(2);
iom.schedule(run);
return 0;
}
服务器开启,等待连接

使用curl向服务器发送请求,可以看到返回了hello,服务器也打印了连接信息


总结
之后写HttpServer可以继承该TcpServer类




严肃观看中……୧(๑•̀⌄•́๑)૭