Reactor 模式是⼀种事件驱动的编程模式,⽤于⾼效地处理并发 I/O 操作。它通过⼀个或多个事件循环(Event Loop)来监听和处理各种事件(如⽹络请求、定时器事件等),从⽽实现⾼效的并发处理,⽽⽆需为每个连接创建⼀个线程或进程。
单线程Reactor反应堆模式Demo
业务层
以计算器为例
cpp
#pragma once
#include "Protocol.hpp"
#include <iostream>
#include <string>
class Calculator
{
public:
Calculator() {}
Response Exec(Request &req)
{
Response resp;
switch (req.Oper())
{
case '+':
resp.SetResult(req.X() + req.Y());
break;
case '-':
resp.SetResult(req.X() - req.Y());
break;
case '*':
resp.SetResult(req.X() * req.Y());
break;
case '/':
{
if (req.Y() == 0)
{
resp.SetCode(1); // 1:div 0 problem
}
else
resp.SetResult(req.X() / req.Y());
}
break;
case '%':
{
if (req.Y() == 0)
{
resp.SetCode(2); // 2:mod 0 problem
}
else
resp.SetResult(req.X() % req.Y());
}
break;
default:
resp.SetCode(3);//3:非法操作
break;
}
return resp;
}
~Calculator() {}
};
Connection.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include<functional>
#include "InetAddr.hpp"
#include "logger.hpp"
class Reactor;
using callback_t =std::function<std::string (std::string &inbuffer)>;
class Connection
{
public:
Connection():_events(0),_owner(nullptr)
{
}
virtual void Recver() = 0;
virtual void Sender() = 0;
virtual void Excepter() = 0;
virtual ~Connection() {}
int SockFd() { return _sockfd; }
void SetSocketfd(int sockfd) { _sockfd = sockfd; }
void SetEvents(uint32_t events) { _events = events; }
uint32_t GetEvents() { return _events; }
void SetAddr(const InetAddr &addr) { _peer = addr; }
Reactor *Owner(){return _owner;}
void SetOwner(Reactor *r){_owner=r;}
void SetCallback(callback_t cb){_cb=cb;}
protected:
int _sockfd;
uint32_t _events;
std::string _inbuffer;
std::string _outbuffer;
InetAddr _peer;
Reactor *_owner; //回指指针,方便我们添加或者使用Reactor中的方法
callback_t _cb;
};
Epoller.hpp
cpp
#pragma once
#include <iostream>
#include <sys/epoll.h>
#include"Util.hpp"
#include "logger.hpp"
class Epoller
{
private:
int OperEventHelper(int sockfd, uint32_t events, int oper)
{
struct epoll_event ev;
ev.events = events;
ev.data.fd = sockfd;
return epoll_ctl(_epfd, oper, sockfd, &ev);
}
public:
Epoller()
{
_epfd = epoll_create(128);
if (_epfd < 0)
{
LOG(LoggerLevel::FATAL) << "epoll create fatal!";
exit(1);
}
LOG(LoggerLevel::INFO) << "create epoll fd success: " << _epfd;
}
void AddEvent(int sockfd, uint32_t events)
{
int n = OperEventHelper(sockfd, events, EPOLL_CTL_ADD);
if (n != 0)
{
LOG(LoggerLevel::INFO) << "Mod: " << sockfd << " events: "
<< Event2String(events) << " to epoller failed!!!";
return;
}
LOG(LoggerLevel::INFO) << "Mod: " << sockfd << " events: "
<< Event2String(events) << " to epoller success!";
}
void DelEvent(int sockfd)
{
int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
if (n != 0)
{
LOG(LoggerLevel::INFO) << "Delete: " << sockfd << " from epoller failed!!!";
return;
}
LOG(LoggerLevel::INFO) << "Delete: " << sockfd << " from epoller success!";
}
void ModEvent(int sockfd, uint32_t events)
{
int n = OperEventHelper(sockfd, events, EPOLL_CTL_MOD);
if (n != 0)
{
LOG(LoggerLevel::INFO) << "add " << sockfd << " events: "
<< Event2String(events) << " to epoller failed!!!";
return;
}
LOG(LoggerLevel::INFO) << "add " << sockfd << " events: "
<< Event2String(events) << " to epoller success!";
}
int Wait(struct epoll_event revs[], int num, int timeout)
{
int n = epoll_wait(_epfd, revs, num, timeout);
(void)n;
return n;
}
~Epoller()
{
if (_epfd >= 0)
{
close(_epfd);
}
}
private:
int _epfd;
};
// class Poller
// {
// public:
// virtual ~Poller()
// {}
// virtual void AddEvent()=0;
// virtual void DelEvent()=0;
// virtual void ModEvent()=0;
// };
// class Selector :public Poller
// {
// };
// class Pollor :public Poller
// {
// };
// class Epollor :public Poller
// {
// };
InetAddr.hpp
cpp
#pragma once
// 该类 用于描述客户端套接字信息
// 方便后续用来管理客户端
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define Conv(addr) ((struct sockaddr*)&addr)
class InetAddr
{
private:
void Net2Host()
{
_port = ntohs(_addr.sin_port);
// _ip = inet_ntoa(_addr.sin_addr);
char ipbuffer[64];
inet_ntop(AF_INET,&(_addr.sin_addr),ipbuffer,strlen(ipbuffer));
_ip=ipbuffer;
}
void Host2Net()
{
memset(&_addr, 0, sizeof(_addr));
_addr.sin_family = AF_INET;
_addr.sin_port = htons(_port);
// _addr.sin_addr.s_addr = inet_addr(_ip.c_str());
inet_pton(AF_INET,_ip.c_str(),&(_addr.sin_addr));
}
public:
InetAddr()
{
}
// 网络风格地址构造
InetAddr(const struct sockaddr_in &addr)
: _addr(addr)
{
Net2Host();
}
// 主机地址风格构造
InetAddr(uint16_t port, const std::string &ip = "0.0.0.0")
: _port(port), _ip(ip)
{
Host2Net();
}
void Init(const struct sockaddr_in &addr)
{
_addr=addr;
Net2Host();
}
std::string Ip()
{
return _ip;
}
uint16_t Port()
{
return _port;
}
struct sockaddr* Addr()
{
return Conv(_addr);
}
socklen_t Length()
{
return sizeof(_addr);
}
std::string ToString()
{
return _ip+"-"+std::to_string(_port);
}
bool operator==(const InetAddr&addr)
{
return _ip==addr._ip&&_port==addr._port;
//return _ip==addr._ip;
}
~InetAddr()
{
}
private:
struct sockaddr_in _addr; // 网络风格地址
// 主机风格地址
std::string _ip;
uint16_t _port;
};
Listener.hpp
cpp
#pragma once
#include<iostream>
#include<memory>
#include<sys/epoll.h>
#include"InetAddr.hpp"
#include"Connection.hpp"
#include"Socket.hpp"
#include"ProcessIO.hpp"
#include"Util.hpp"
//连接管理器,创建listen,获取新连接
class Listener :public Connection
{
public:
Listener(uint16_t port)
:_listensockfd(std::make_unique<TcpSocket>()),
_port(port)
{
_listensockfd->BuildListenSocketMethod(_port);
SetSocketfd(_listensockfd->SockFd());
SetEvents(EPOLLIN | EPOLLET); //EPOLLET:对应的sockfd必须非阻塞
}
void Recver() override
{
// LOG(LoggerLevel::DEBUG)<<"事件派发成功后,会回调到这里";
//获取新连接,非阻塞循环获取,因为ET模式只通知一次,保证一次全部处理完
while(true)
{
InetAddr clientaddr;
int error=0;
int sockfd=_listensockfd->Accept(&clientaddr,&error);
if(sockfd<0)
{
if(errno==EAGAIN)
break;
else if(errno==EINTR)
continue;
else
break;
}
//获取新连接成功,不能直接读取,先添加到Reactor中
//1.构建新的连接
SetNonBlock(sockfd);
std::shared_ptr<Connection> conn=std::make_shared<ProcessIO>(sockfd,clientaddr);
conn->SetCallback(_cb);
//2.添加到Reactor中
Owner()->AddConnection(conn);
}
}
void Sender() override
{
//empty
}
void Excepter() override
{
//empty
}
~Listener(){}
private:
std::unique_ptr<Socket> _listensockfd;
uint16_t _port;
};
logger.hpp
cpp
#pragma once
#include <iostream>
#include <filesystem>
#include <fstream>
#include <string>
#include <sstream>
#include <memory>
#include <unistd.h>
#include "Mutex.hpp"
enum class LoggerLevel
{
DEBUG,
INFO,
WARNING,
ERROR,
FATAL
};
std::string LoggerLevelToString(LoggerLevel level)
{
switch (level)
{
case LoggerLevel::DEBUG:
return "Debug";
case LoggerLevel::INFO:
return "Info";
case LoggerLevel::WARNING:
return "Warning";
case LoggerLevel::ERROR:
return "Error";
case LoggerLevel::FATAL:
return "Fatal";
default:
return "Unknown";
}
}
std::string GetCurrentTime()
{
// 获取时间戳
time_t timep = time(nullptr);
// 把时间戳转化为时间格式
struct tm currtm;
localtime_r(&timep, &currtm);
// 转化为字符串
char buffer[64];
snprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d-%02d-%02d",
currtm.tm_year + 1900, currtm.tm_mon + 1, currtm.tm_mday,
currtm.tm_hour, currtm.tm_min, currtm.tm_sec);
return buffer;
}
class LogStrategy
{
public:
virtual ~LogStrategy() = default;
virtual void SyncLog(const std::string &logmessage) = 0;
};
// 显示器刷新
class ConsoleLogStrategy : public LogStrategy
{
public:
~ConsoleLogStrategy()
{
}
virtual void SyncLog(const std::string &logmessage) override
{
{
LockGuard lockguard(&_lock);
std::cout << logmessage << std::endl;
}
}
private:
Mutex _lock;
};
const std::string default_dir_path_name = "/var/log/";
const std::string default_filename = "test.log";
// 文件刷新
class FileLogStrategy : public LogStrategy
{
public:
FileLogStrategy(const std::string dir_path_name = default_dir_path_name,
const std::string filename = default_filename)
: _dir_path_name(dir_path_name), _filename(filename)
{
if (std::filesystem::exists(_dir_path_name))
{
return;
}
try
{
std::filesystem::create_directories(_dir_path_name);
}
catch (const std::filesystem::filesystem_error &e)
{
std::cerr << e.what() << "\r\n";
}
}
~FileLogStrategy()
{
}
virtual void SyncLog(const std::string &logmessage) override
{
{
LockGuard lock(&_lock);
std::string target = _dir_path_name;
target += '/';
target += _filename;
std::ofstream out(target.c_str(), std::ios::app);
if (!out.is_open())
{
return;
}
out << logmessage << "\n";
out.close();
}
}
private:
std::string _dir_path_name;
std::string _filename;
Mutex _lock;
};
class Logger
{
public:
Logger()
{
}
void EnableConsoleStrategy()
{
_strategy = std::make_unique<ConsoleLogStrategy>();
}
void EnableFileStrategy()
{
_strategy = std::make_unique<FileLogStrategy>();
}
class LogMessage
{
public:
LogMessage(LoggerLevel level, std::string filename, int line, Logger& logger)
: _curr_time(GetCurrentTime()), _level(level), _pid(getpid())
, _filename(filename), _line(line), _logger(logger)
{
std::stringstream ss;
ss << "[" << _curr_time << "] "
<< "[" << LoggerLevelToString(_level) << "] "
<< "[" << _pid << "] "
<< "[" << _filename << "] "
<< "[" << _line << "]"
<< " - ";
_loginfo = ss.str();
}
template <typename T>
LogMessage &operator<<(const T &info)
{
std::stringstream ss;
ss << info;
_loginfo += ss.str();
return *this;
}
~LogMessage()
{
if (_logger._strategy)
{
_logger._strategy->SyncLog(_loginfo);
}
}
private:
std::string _curr_time; // 时间戳
LoggerLevel _level; // 日志等级
pid_t _pid; // 进程pid
std::string _filename; // 文件名
int _line; // 行号
std::string _loginfo; // 一条合并完成的,完整的日志信息
Logger &_logger; // 提供刷新策略的具体做法
};
LogMessage operator()(LoggerLevel level, std::string filename, int line)
{
return LogMessage(level, filename, line, *this);
}
~Logger()
{
}
private:
std::unique_ptr<LogStrategy> _strategy;
};
Logger logger;
#define LOG(level) logger(level, __FILE__, __LINE__)
#define EnableConsoleStrategy() logger.EnableConsoleStrategy()
#define EnableFileStrategy() logger.EnableFileStrategy()
Mutex.hpp
cpp
#pragma once
#include <iostream>
#include <mutex>
#include <pthread.h>
class Mutex
{
public:
Mutex()
{
pthread_mutex_init(&_lock, nullptr);
}
void Lock()
{
pthread_mutex_lock(&_lock);
}
pthread_mutex_t *Get()
{
return &_lock;
}
void Unlock()
{
pthread_mutex_unlock(&_lock);
}
~Mutex()
{
pthread_mutex_destroy(&_lock);
}
private:
pthread_mutex_t _lock;
};
class LockGuard
{
public:
LockGuard(Mutex *_mutex) : _mutexp(_mutex)
{
_mutex->Lock();
}
~LockGuard()
{
_mutexp->Unlock();
}
private:
Mutex *_mutexp;
};
Parser.hpp
cpp
#pragma once
#include "Protocol.hpp"
#include"logger.hpp"
#include <iostream>
#include <string>
#include<functional>
using handler_t=std::function<Response(Request &req)>;
//只负责对报文进行各种解析工作
//解析出的具体业务交给服务端
class Parser
{
public:
Parser(handler_t handler): _handler(handler)
{}
std::string Parse(std::string &inbuffer)
{
std::string send_str;
while (true)
{ // 1.解析报文
std::string jsonstr;
// Unpack第二个参数是输入输出参数
int n = Protocol::Unpack(inbuffer, &jsonstr);
if (n < 0)
{
break;
// exit(0);
}
else if (n == 0)
break; // 全部处理完毕!
else
{
LOG(LoggerLevel::DEBUG)<<"\r\n"<<jsonstr;
Request req;
// 2.反序列化
if (!req.Deserialize(jsonstr))
{
return std::string();
}
// 3.根据req->response,具体的业务
Response resp = _handler(req);
// 4.计算结果返回给客户端
// 对resp做序列化
std::string resp_json;
// Serialize参数也是一个输入输出型参数
if (!resp.Serialize(&resp_json))
{
return std::string();
}
// 5.打包,然后发给客户端
send_str += Protocol::Package(resp_json);
}
}
// 6.发回客户端
return send_str;
}
~Parser() {}
private:
handler_t _handler;
};
ProcessIO.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include "Connection.hpp"
#include "Epoller.hpp"
class ProcessIO : public Connection
{
static const int buffer_size = 1024;
public:
ProcessIO(int sockfd, InetAddr &addr)
{
SetSocketfd(sockfd);
SetAddr(addr);
SetEvents(EPOLLIN | EPOLLET);
}
void Recver() override
{
// LOG(LoggerLevel::DEBUG)<<"发送了数据";
while (true)
{
char buffer[buffer_size];
ssize_t n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0); // 非阻塞的
if (n > 0)
{
buffer[n] = 0;
_inbuffer += buffer;
}
else if (n == 0)
{
// 异常处理
LOG(LoggerLevel::INFO) << "client quit,client is: " << _peer.ToString();
Excepter();
return;
}
else
{
if (errno == EAGAIN)
{
break;
}
else if (errno == EINTR)
{
continue;
}
else
{
LOG(LoggerLevel::INFO) << "recv error,client is: " << _peer.ToString();
Excepter();
return;
}
}
}
//到这本轮数据全部读完
// std::cout<<"我要看到任意一个sockfd对应的inbuffer内容是追加写入的: "<<
// _peer.ToString()<<"# "<< _inbuffer;
//交给协议检查完整报文
_outbuffer+=_cb(_inbuffer);
std::cout<<"_outbuffer: "<<_outbuffer<<std::endl;
//方案二:使能写关心,只要开启写事件关心,无论写是否就绪,都会默认触发一次
if(!_outbuffer.empty())
Owner()->EnableReadWrite(_sockfd,true,true);
//如何发送?方案一:最佳实践,直接发
// if(!_outbuffer.empty())
// Sender();
}
void Sender() override
{
while(true)
{
ssize_t n=send(_sockfd,_outbuffer.c_str(),_outbuffer.size(),0);
if(n>0)
{
_outbuffer.erase(0,n);
if(_outbuffer.size()==0)break;
}
else if(n==0)
{
break;
}
else{
if(errno==EAGAIN)break;
else if(errno==EINTR)continue;
else
{
Excepter();
return;
}
}
if(!_outbuffer.empty())
{
//2.缓冲区被写满了
//开启sockfd对写事件的关心
Owner()->EnableReadWrite(_sockfd,true,true);
}
else
{
//1.发完了
//关闭对sockfd写事件的关心
Owner()->EnableReadWrite(_sockfd,true,false);
}
}
}
void Excepter() override
{
//统一错误处理
Owner()->DelConnection(_sockfd);
}
private:
};
Protocol.hpp
cpp
#pragma once
#include<iostream>
#include<string>
#include<jsoncpp/json/json.h>
//jsonstr\r\n
class Request
{
public:
Request():_x(0),_y(0),_oper(0)
{}
//序列化
bool Serialize(std::string *out)
{
Json::Value root;
root["x"]=_x;
root["y"]=_y;
root["oper"]=_oper;
Json::StyledWriter writer;
*out=writer.write(root);
if(out->empty())
return false;
return true;
}
//反序列化
bool Deserialize(std::string &in)
{
Json::Reader reader;
Json::Value root;
bool ret=reader.parse(in,root);
if(!ret)
return false;
_x=root["x"].asInt();
_y=root["y"].asInt();
_oper=root["oper"].asInt();//没有asChar,使用asInt,放到char类型就会自动解析了
return true;
}
int X()
{
return _x;
}
int Y()
{
return _y;
}
char Oper()
{
return _oper;
}
~Request()
{
}
public:
// _x _oper _y ---约定1
int _x;
int _y;
char _oper;
};
class Response
{
public:
Response():_result(0),_code(0)
{
}
//序列化
bool Serialize(std::string *out)
{
Json::Value root;
root["result"]=_result;
root["code"]=_code;
Json::StyledWriter writer;
*out=writer.write(root);
if(out->empty())
return false;
return true;
}
//反序列化
bool Deserialize(std::string &in)
{
Json::Reader reader;
Json::Value root;
bool ret=reader.parse(in,root);
if(!ret)
return false;
_result=root["result"].asInt();
_code=root["code"].asInt();
return true;
}
void SetResult(int r)
{
_result=r;
}
void SetCode(int c)
{
_code=c;
}
void Print()
{
std::cout<<_result<<"["<<_code<<"]"<<std::endl;
}
~Response()
{
}
public://加快访问,如果设置为private还要public写getResult之类的函数
int _result; //存在除零问题,设置错误码解决
int _code; //可信度 //错误码0 1:0表示可信,1表示出错
};
static const std::string sep="\r\n";
class Protocol
{
public:
static std::string Package(const std::string &jsonstr)
{
//jsonstr -> len\r\njsonstr\r\n
if(jsonstr.empty())
return std::string();
std::string json_length=std::to_string(jsonstr.size());
return json_length+sep+jsonstr+sep;
}
//static消除this影响
static bool DigitSafeCheck(const std::string str)
{
for(auto&ch:str)
{
if(!(ch>='0'&&ch<='9'))
return false;
}
return true;
}
//存在粘包问题,获取到的报文以及报文对应的数据可能不完整
//[当前报文长度][分隔符][实际数据][分隔符]
//eg::
//len\r\njsonstr\r\n
//len\r\njsonstr\r\nlen\r\njsonstr\r\n
//len\r\njsonstr
//len\r
//...
//str:从网络读取上来的字符串,这里将其设置为输入输出参数
//package:输出型参数,如果有完整的json报文,就返回
static int Unpack(std::string &origin_str,std::string *package)
{
if(!package)
return 0;
auto pos=origin_str.find(sep);//从左往右查找第一个分隔符
if(pos==std::string::npos)
return 0;
//此时我们收到了该报文的长度
std::string len_str=origin_str.substr(0,pos);
if(!DigitSafeCheck(len_str))
{
//<0解析错误
return -1;
}
//计算报文对应的数据的长度
int digit_len=std::stoi(len_str);
//计算报文完整长度
int target_len=len_str.size()+digit_len+2*sep.size();
//特判读取不全
if(origin_str.size()<target_len)
return 0;
//此时我们接受到的就是完整报文
//package存储报文数据
*package=origin_str.substr(pos+sep.size(),digit_len);
//移除掉当前报文
origin_str.erase(0,target_len);
return package->size();
}
};
Reactor.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include"Util.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Socket.hpp"
// Reactor:反应堆,本质是一个 利用多路转接,激活自己所管理的一个一个节点Connection的 容器
class Reactor
{
static const int gsize = 128;
private:
bool IsExist(std::shared_ptr<Connection> &conn)
{
auto iter = _connections.find(conn->SockFd());
return iter != _connections.end();
}
bool IsExist(int sockfd)
{
auto iter = _connections.find(sockfd);
return iter != _connections.end();
}
public:
Reactor() : _epoller(std::make_unique<Epoller>())
{
}
void AddConnection(std::shared_ptr<Connection> &conn)
{
if (IsExist(conn))
{
LOG(LoggerLevel::INFO) << conn->SockFd() << " conn already in Reactor...";
return;
}
// 0.让conn回指向当前的reactor
conn->SetOwner(this);
// 1.conn先插入到 _connections
_connections.insert(std::make_pair(conn->SockFd(), conn));
// 2. conn->sockfd,event 写透到内核中 _epoller来做
_epoller->AddEvent(conn->SockFd(), conn->GetEvents());
LOG(LoggerLevel::INFO) << conn->SockFd() << " conn add to Reactor";
}
void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
{
if (!IsExist(sockfd))
{
LOG(LoggerLevel::WARNING) << sockfd << " conn is not in Reactor,bug!";
return;
}
// 1. 修改connection对象
uint32_t events = (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT : 0) | EPOLLET;
_connections[sockfd]->SetEvents(events);
// 2. 写透到内核
// _epoller->ModEvent(_connections[sockfd]->SockFd(),_connections[sockfd]->GetEvents());
_epoller->ModEvent(sockfd,events);
}
void DelConnection(int sockfd)
{
if(!IsExist(sockfd))
{
LOG(LoggerLevel::WARNING)<<sockfd<<" conn is not in Reactor[delete]!";
return;
}
//1.从内核移除对sockfd的关心,该步骤必须先做
_epoller->DelEvent(sockfd);
//2.close关闭fd
close(sockfd);
//3._connections移除到kv
_connections.erase(sockfd);
LOG(LoggerLevel::INFO)<<"remove conn "<<sockfd<<" from reactor success!!!";
}
void LoopOnce(int timeout)
{
int n = _epoller->Wait(revs, gsize, timeout);
for (int i = 0; i < n; ++i)
{
int sockfd = revs[i].data.fd;
uint32_t events = revs[i].events;
// 统一报错处理逻辑
if ((events & EPOLLHUP) || (events & EPOLLERR))
events = (EPOLLIN | EPOLLOUT);
// 鲁棒性
if ((events & EPOLLIN) && IsExist(sockfd))
{
_connections[sockfd]->Recver();
}
if ((events & EPOLLOUT) && IsExist(sockfd))
{
_connections[sockfd]->Sender();
}
}
}
void EventsDispatcher()
{
int timeout = 1000; // ms
while (true)
{
// 处理事件
LoopOnce(timeout);
ShowConnection();
// 连接管理
// CheckTimeOut();
}
}
void ShowConnection()
{
std::cout<<"###############################"<<std::endl;
for(auto&conn:_connections)
{
std::cout<<conn.second->SockFd()<<" : "
<<Event2String(conn.second->GetEvents())<<std::endl;
}
std::cout<<"###############################"<<std::endl;
}
~Reactor()
{
}
private:
std::unordered_map<int, std::shared_ptr<Connection>> _connections;
std::unique_ptr<Epoller> _epoller;
struct epoll_event revs[gsize];
};
Socket.hpp
cpp
#ifndef __SOCKET_HPP__
#define __SOCKET_HPP__
#include<iostream>
#include<string>
#include<unistd.h>
#include<cstdio>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<memory>
#include"logger.hpp"
#include"InetAddr.hpp"
#include"Util.hpp"
enum
{
OK,
CREATE_ERR,
BIND_ERR,
LISTEN_ERR,
ACCEPT_ERR,
};
static int gbacklog =16;
static const int gsockfd=-1;
//设计模式:模块方法模式
//基类定义骨架流程
//子类实现具体步骤
class Socket
{
public:
//Socket *sock=new TcpSocket();
//基类虚构设置为虚函数,目的是保证子类资源能析构,然后再析构基类资源,如果不是虚函数子类析构会被跳过
virtual ~Socket(){}
//定义子类必须实现的抽象接口,do what?(相当于是函数声明,函数定义在子类完成)
//virtual ...=0纯虚函数
//目的:
//1:强制子类实现这个函数(如果该类不需要这个函数就做个空函数)否则编译报错;
//2.使基类变成抽象类,基类不能创建对象,只能通过子类创建
virtual void CreateSocketOrDie()=0;
virtual void BindSocketOrDie(int port)=0;
virtual void ListenSocketOrDie(int backlog)=0;
// virtual std::shared_ptr<Socket> Accept(InetAddr *clientaddr)=0;
virtual int Accept(InetAddr *clientaddr,int *error)=0;
virtual int SockFd()=0;
virtual void Close()=0;
virtual ssize_t Recv(std::string *out)=0;
virtual ssize_t Send(const std::string &in)=0;
virtual bool Connect(InetAddr &peer)=0;
//other...
public:
//基于抽象接口构建的通用逻辑,How to do?
//方便复用通用流程
void BuildListenSocketMethod(int _port)
{
CreateSocketOrDie();
BindSocketOrDie(_port);
ListenSocketOrDie(gbacklog);
}
void BuildClientSocketMethod()
{
CreateSocketOrDie();
}
// void BuildUdpSocketMethod()
// {
// CreateSocketOrDie();
// BindSocketOrDie();
// }
// void BuildTcpSocketMethod()
// {
// CreateSocketOrDie();
// BindSocketOrDie();
// ListenSocketOrDie();
// }
};
class TcpSocket:public Socket
{
public:
TcpSocket()
:_sockfd(gsockfd)
{
}
TcpSocket(int sockfd):_sockfd(sockfd)
{
}
void CreateSocketOrDie() override
{
_sockfd=socket(AF_INET,SOCK_STREAM,0);
if(_sockfd<0)
{
LOG(LoggerLevel::FATAL)<<"create socket error!";
exit(CREATE_ERR);
}
SetNonBlock(_sockfd);
int opt=1;
setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));
LOG(LoggerLevel::INFO)<<"create socket success!!!";
}
void BindSocketOrDie(int port) override
{
InetAddr local(port);
if(bind(_sockfd,local.Addr(),local.Length())!=0)
{
LOG(LoggerLevel::FATAL)<<"bind socker error!";
exit(BIND_ERR);
}
LOG(LoggerLevel::INFO)<<"bind socket success!!!";
}
void ListenSocketOrDie(int backlog) override
{
if(listen(_sockfd,backlog)!=0)
{
LOG(LoggerLevel::FATAL)<<"listen socker error!";
exit(LISTEN_ERR);
}
LOG(LoggerLevel::INFO)<<"listen socket success!!!";
}
// std::shared_ptr<Socket> Accept(InetAddr *clientaddr) override
int Accept(InetAddr *clientaddr,int*error) override
{
struct sockaddr_in peer;
socklen_t len=sizeof(peer);
int fd=accept(_sockfd,(struct sockaddr*)&peer,&len);
*error=errno;
if(fd<0)
{
LOG(LoggerLevel::WARNING)<<"accept socker Done!";
return -1;
}
LOG(LoggerLevel::INFO)<<"accept socket success!!!";
clientaddr->Init(peer);
return fd;
// return std::make_shared<TcpSocket>(fd);
}
int SockFd() override
{
return _sockfd;
}
void Close() override
{
if(_sockfd>=0)
close(_sockfd);
}
ssize_t Recv(std::string *out) override
{
//只读一次
char buffer[1024];
ssize_t n=recv(_sockfd,buffer,sizeof(buffer)-1,0);
if(n>0)
{
buffer[n]=0;
*out+=buffer;
}
return n;
}
ssize_t Send(const std::string &in) override
{
return send(_sockfd,in.c_str(),in.size(),0);
}
bool Connect(InetAddr &peer) override
{
int n=connect(_sockfd,peer.Addr(),peer.Length());
if(n>=0)return true;
return false;
}
~TcpSocket()
{
}
private:
int _sockfd;
};
// class UdpSocket:public Socket
// {
// };
#endif
Util.hpp
cpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
void SetNonBlock(int fd)
{
int fl = fcntl(fd, F_GETFL);
if (fl < 0)
{
return;
}
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}
std::string Event2String(uint32_t events)
{
std::string s;
if (events & EPOLLIN)
s = "EPOLLIN";
if (events & EPOLLOUT)
s += " | EPOLLOUT";
if (events & EPOLLET)
s += " | EPOLLET";
//...
return s;
}
Makefile
cpp
reactor_server:Main.cc
g++ -o $@ $^ -std=c++17 -ljsoncpp
.PHONY:clean
clean:
rm -f reactor_server
Main.cc
cpp
#include <iostream>
#include "Calculator.hpp"
#include "Protocol.hpp"
#include "Parser.hpp"
#include "logger.hpp"
#include "Reactor.hpp"
//Reactor在Listener前面
#include "Listener.hpp"
void Usage(std::string proc)
{
std::cerr << "Usage: " << proc << " localport" << std::endl;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
Usage(argv[0]);
exit(0);
}
// 网络服务 -port
uint16_t serverport = std::stoi(argv[1]);
// 日志服务
EnableConsoleStrategy();
// 1.业务对象
std::unique_ptr<Calculator> cal = std::make_unique<Calculator>();
// 2.协议和解析协议对象
std::unique_ptr<Parser> parse_protocol = std::make_unique<Parser>(
[&cal](Request &req) -> Response
{
return cal->Exec(req);
});
// 3.连接管理器 - Listener
std::shared_ptr<Connection> listener = std::make_shared<Listener>(serverport);
listener->SetCallback([&parse_protocol](std::string &inbuffer)->std::string{
return parse_protocol->Parse(inbuffer);
});
// 4.构建一个Reactor容器
std::unique_ptr<Reactor> R = std::make_unique<Reactor>();
// 给reactor中,将连接管理器添加到Reactor中
R->AddConnection(listener);
// 启动Reactor
R->EventsDispatcher();
return 0;
}
多线程未完待续...
2025.12.7 大雪 至此Linux完结撒花
接下来就是复习了