Linux网络编程:Reactor反应堆模式

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完结撒花

接下来就是复习了

相关推荐
xxp43211 小时前
Linux 根文件系统构建
linux·学习
边疆.1 小时前
【Linux】文件系统
linux·运维·服务器·磁盘·文件系统·软硬链接
霸王大陆1 小时前
《零基础学PHP:从入门到实战》教程-模块八:面向对象编程(OOP)入门-5
开发语言·笔记·php·课程设计
大神的风范1 小时前
LINUX 驱动之HSR04超声波模块,设备树配置
linux·驱动开发
盛满暮色 风止何安1 小时前
负责均衡的理解
运维·服务器·网络·网络协议·系统安全·安全架构
雨中飘荡的记忆1 小时前
Step Builder模式实战
java·设计模式
wyjcxyyy1 小时前
2025polar冬季赛复盘(WEB,MISC)
运维·服务器
HealthScience2 小时前
vscode通过跳板机连接到服务器
服务器·ide·vscode
知识分享小能手2 小时前
CentOS Stream 9入门学习教程,从入门到精通,CentOS Stream 9 进程管理 —语法详解与实战案例(8)
linux·学习·centos