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

接下来就是复习了

相关推荐
静水流深_沧海一粟16 小时前
04 | 别再写几十个参数的构造函数了——建造者模式
设计模式
StarkCoder16 小时前
从UIKit到SwiftUI的迁移感悟:数据驱动的革命
设计模式
chlk1231 天前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑1 天前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件1 天前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
阿星AI工作室1 天前
给openclaw龙虾造了间像素办公室!实时看它写代码、摸鱼、修bug、写日报,太可爱了吧!
前端·人工智能·设计模式
BingoGo1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
深紫色的三北六号1 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash2 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)