Linux网络---Epoll-Reactor模式

Channel.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <memory>
#include <functional>
#include "Common.hpp"
#include "Connection.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogModule;

#define SIZE 1024

// 普通sockfd的封装
class Channel : public Connection
{
public:
    Channel(int sockfd, const InetAddr &client) : _sockfd(sockfd), _client_addr(client)
    {
        SetNonBlock(_sockfd);
    }

    void Recver() override
    {
        // 我们读到的是字符串
        char buffer[SIZE];
        while (true)
        {
            buffer[0] = 0;                                            // 清空字符串
            ssize_t n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0); // 非阻塞读取的
            if (n > 0)
            {
                buffer[n] = 0;
                _inbuffer += buffer; // 接受缓冲区中,入队列的过程
            }
            else if (n == 0)
            {
                Excepter();
                return;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }
        LOG(LogLevel::DEBUG) << "Channel: Inbuffer:\n"
                             << _inbuffer;
        if (!_inbuffer.empty())
            _outbuffer += _handler(_inbuffer); // 和protocol相关的匿名函数里面!

        if (!_outbuffer.empty())
        {
            Sender(); // 最佳实践
            //GetOwner()->EnableReadWrite(_sockfd, true, true);
        }
       
    }
    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.empty())
                    break;
            }
            else if (n == 0)
            {
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                if (errno == EINTR)
                    continue;
                else
                {
                    Excepter();
                    return;
                }
            }
        }

        // 1. 数据发送完毕
        // 2. 发送条件不具备
        if (!_outbuffer.empty())
        {
            // 开启对写事件的关心
            GetOwner()->EnableReadWrite(_sockfd, true, true);
        }
        else
        {
            GetOwner()->EnableReadWrite(_sockfd, true, false);
        }
    }
    void Excepter() override
    {
        // 所有的异常,都被我归一到了这个函数内部!!
        GetOwner()->DelConnection(_sockfd);
    }
    int GetSockFd() override
    {
        return _sockfd;
    }
    std::string &Inbuffer()
    {
        return _inbuffer;
    }
    void AppendOutBuffer(const std::string &out)
    {
        _outbuffer += out;
    }
    ~Channel()
    {
    }

private:
    int _sockfd;
    std::string _inbuffer; // 充当缓冲区,vector<char>
    std::string _outbuffer;
    InetAddr _client_addr;

    // handler_t _handler;
};

Connection.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <string>
#include "InetAddr.hpp"

// 封装fd,保证给每一个fd一套缓冲
class Reactor;
class Connection;

using handler_t = std::function<std::string (std::string &)>;

// 基类
class Connection
{
public:
    Connection():_events(0), _owner(nullptr)
    {
    }
    void SetEvent(const uint32_t &events)
    {
        _events = events;
    }
    uint32_t GetEvent()
    {
        return _events;
    }
    void SetOwner(Reactor *owner)
    {
        _owner = owner;
    }
    Reactor *GetOwner()
    {
        return _owner;
    }
    virtual void Recver() = 0;
    virtual void Sender() = 0;
    virtual void Excepter() = 0;
    virtual int GetSockFd() = 0;

    void RegisterHandler(handler_t handler)
    {
        _handler = handler;
    }
    ~Connection()
    {
    }

private:
    // 关心事件
    uint32_t _events;

    // 回指指针
    Reactor *_owner;

public:
    handler_t _handler; // 基类中定义了一个回调函数
};

Epoller.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <string>
#include "InetAddr.hpp"

// 封装fd,保证给每一个fd一套缓冲
class Reactor;
class Connection;

using handler_t = std::function<std::string (std::string &)>;

// 基类
class Connection
{
public:
    Connection():_events(0), _owner(nullptr)
    {
    }
    void SetEvent(const uint32_t &events)
    {
        _events = events;
    }
    uint32_t GetEvent()
    {
        return _events;
    }
    void SetOwner(Reactor *owner)
    {
        _owner = owner;
    }
    Reactor *GetOwner()
    {
        return _owner;
    }
    virtual void Recver() = 0;
    virtual void Sender() = 0;
    virtual void Excepter() = 0;
    virtual int GetSockFd() = 0;

    void RegisterHandler(handler_t handler)
    {
        _handler = handler;
    }
    ~Connection()
    {
    }

private:
    // 关心事件
    uint32_t _events;

    // 回指指针
    Reactor *_owner;

public:
    handler_t _handler; // 基类中定义了一个回调函数
};

Listener.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <memory>
#include "Epoller.hpp"
#include "Socket.hpp"
#include "Common.hpp"
#include "Connection.hpp"
#include "Channel.hpp"

using namespace SocketModule;

// Listener 专门进行获取新连接
class Listener : public Connection
{
public:
    Listener(int port = defaultport)
    :_port(port), _listensock(std::make_unique<TcpSocket>())
    {
        _listensock->BuildTcpSocketMethod(_port);
        SetEvent(EPOLLIN | EPOLLET); //ET todo
        SetNonBlock(_listensock->Fd());
    }
    ~Listener()
    {}
    void Recver() override
    {
        //accept
        //LOG(LogLevel::DEBUG) << "进入Listener模块的Recver函数";
        InetAddr client;
        while(true)
        {
            int sockfd = _listensock->Accept(&client);
            if(sockfd == ACCEPT_ERR)
                break;
            else if(sockfd == ACCEPT_CONTINUE)
                continue;
            else if(sockfd == ACCEPT_DONE)
                break;
            else
            {
                // 我们获得的是一个合法的fd,普通的文件描述符
                std::shared_ptr<Connection> conn = std::make_shared<Channel>(sockfd, client);
                conn->SetEvent(EPOLLIN|EPOLLET);
                if(_handler != nullptr)
                    conn->RegisterHandler(_handler);
                GetOwner()->AddConnection(conn);
            }
        }
    }
    void Sender() override
    {}
    void Excepter() override
    {}
    int GetSockFd() override
    {
        return _listensock->Fd();
    }
private:
    int _port;
    std::unique_ptr<Socket> _listensock;
};

Reactor.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Log.hpp"

using namespace LogModule;

// 反应堆
class Reactor
{
    static const int revs_num = 128;

private:
    bool IsConnectionExistsHelper(int sockfd)
    {
        auto iter = _connections.find(sockfd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }
    bool IsConnectionExists(const std::shared_ptr<Connection> &conn)
    {
        return IsConnectionExistsHelper(conn->GetSockFd());
    }
    bool IsConnectionExists(int sockfd)
    {
        return IsConnectionExistsHelper(sockfd);
    }
    bool IsConnectionEmpty()
    {
        return _connections.empty();
    }

    int LoopOnce(int timeout)
    {
        return _epoller_ptr->WaitEvents(_revs, revs_num, timeout);
    }

    void Dispatcher(int n) // 事件派发器
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;      // 就绪的fd
            uint32_t revents = _revs[i].events; // 就绪的事件
            // 1. 将所有的异常处理,统一转化成IO错误 2. 所有的IO异常,统一转换成为一个异常处理函数
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT); // 1. 将所有的异常处理,统一转化成IO错误
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT); // 1. 将所有的异常处理,统一转化成IO错误

            if (revents & EPOLLIN)
            {
                // 读事件就绪, 用不用区分是否异常?不用
                // 读事件就绪,还用不用区分是listenfd还是普通socketfd?不用
                if (IsConnectionExists(sockfd))
                    _connections[sockfd]->Recver();
            }
            if (revents & EPOLLOUT)
            {
                // 写事件就绪
                if (IsConnectionExists(sockfd))
                    _connections[sockfd]->Sender();
            }
        }
    }

public:
    Reactor()
        : _epoller_ptr(std::make_unique<Epoller>()),
          _isrunning(false)
    {
    }
    void Loop()
    {
        if (IsConnectionEmpty())
            return;

        _isrunning = true;
        int timeout = -1;
        while (_isrunning)
        {
            PrintConnection(); //debug
            int n = LoopOnce(timeout);
            Dispatcher(n);
        }
        _isrunning = false;
    }
    // 该接口要把所有的新连接添加到_connections,并且,写透到epoll内核中!!!!!
    void AddConnection(std::shared_ptr<Connection> &conn)
    {
        // 0. 不要重复添加
        if (IsConnectionExists(conn))
        {
            LOG(LogLevel::WARNING) << "conn is exists: " << conn->GetSockFd();
            return;
        }

        // 1. conn对应的fd和他要关心的事件,写透到内核中!
        uint32_t events = conn->GetEvent();
        int sockfd = conn->GetSockFd();
        _epoller_ptr->AddEvent(sockfd, events);

        // 2. 设置当前conn的拥有者回指指针
        conn->SetOwner(this);

        // 3. 将具体的connection添加到_connections
        _connections[sockfd] = conn;
    }
    void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
    {
        // 0. 不要重复添加
        if (!IsConnectionExists(sockfd))
        {
            LOG(LogLevel::WARNING) << "EnableReadWrite, conn is exists: " << sockfd;
            return;
        }

        // 1. 修改当前sockfd对应的connection关心的事件
        uint32_t new_event = (EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT:0));
        _connections[sockfd]->SetEvent(new_event);

        // 2. 写透到内核,调整sockfd对特定事件的关心
        _epoller_ptr->ModEvent(sockfd, new_event);
    }
    void DelConnection(int sockfd)
    {
        //1. epoll移除的时候,sockfd必须是合法的
        _epoller_ptr->DelEvent(sockfd);

        //2. 从_connections移除自己
        _connections.erase(sockfd);

        //3. 关闭不要的sockfd
        close(sockfd);

        LOG(LogLevel::INFO) << "client quit: " << sockfd;
    }
    void Stop()
    {
        _isrunning = false;
    }
    void PrintConnection()
    {
        std::cout << "当前Reactor正在进行管理的fd List:";
        for(auto &conn : _connections)
        {
            std::cout << conn.second->GetSockFd() << " ";
        }
        std::cout << "\r\n";
    }
    ~Reactor()
    {
    }

private:
    // 1. epoll模型
    std::unique_ptr<Epoller> _epoller_ptr;
    // 2. 是否启动
    bool _isrunning;
    // 3. 管理所有的connection,本质是管理未来所有我获取到的fd
    // fd : Connection
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    // 4. 就绪的所有事件
    struct epoll_event _revs[revs_num];
};

main.cpp

cpp 复制代码
#include <iostream>
#include <string>
#include "Reactor.hpp"
#include "Listener.hpp"
#include "Channel.hpp"
#include "Log.hpp"
#include "Common.hpp"
#include "Protocol.hpp"
#include "NetCal.hpp"

static void Usage(std::string proc)
{
    std::cerr << "Usage: " << proc << " port" << std::endl;
}

//./server port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }

    LogModule::ConsoleLogStrategy();
    uint16_t port = std::stoi(argv[1]);
    // 构建一个业务模块
    std::shared_ptr<Cal> cal = std::make_shared<Cal>();

    // 构建协议对象
    std::shared_ptr<Protocol> protocol = std::make_shared<Protocol>([&cal](Request &req) -> Response
                                                                    { return cal->Execute(req); });

    // 构建Listener对象
    std::shared_ptr<Connection> conn = std::make_shared<Listener>(port);
    conn->RegisterHandler([&protocol](std::string &inbuffer) -> std::string { // 这个匿名函数就是要被Channel
        LOG(LogLevel::DEBUG) << "进入到匿名函数中...";
        std::string response_str;
        while (true)
        {
            std::string package;
            if (!protocol->Decode(inbuffer, &package))
                break;
            // 我敢保证,我的packge一定是一个完整的请求,是字节流的
            response_str += protocol->Execute(package);
        }
        LOG(LogLevel::DEBUG) << "结束匿名函数中...: " << response_str;
        return response_str;
    });

    // 构建一个reactor模块
    std::unique_ptr<Reactor> R = std::make_unique<Reactor>();
    R->AddConnection(conn);

    R->Loop();

    return 0;
}
相关推荐
larance1 小时前
NebulaGraph 数据库部署与运维指令清单
linux·服务器·数据库
济6172 小时前
ARM Linux 驱动开发篇---内核定时器实验--- Ubuntu20.04
linux·嵌入式·嵌入式linux驱动开发
小尔¥2 小时前
Nginx核心功能
运维·网络·nginx
℡終嚸♂6802 小时前
Goby资产测绘漏洞扫描工具红队版自带1000+poc,以及附赠收集的1000+poc(附下载链接)
安全·web安全·php
燃于AC之乐2 小时前
OpenClaw“小龙虾”深度解析:60天碾压Linux的AI智能体,从原理到搞定本地部署【Windows系统 + 接入飞书】
linux·人工智能·飞书·openclaw·小龙虾
犀思云2 小时前
解构网络复杂性:基于 FusionWAN NaaS 的确定性架构工程实践与流量编排深度指南
网络·人工智能·机器人·智能仓储·专线
进击切图仔2 小时前
Linux 下 USB 设备端口错乱问题排查与解决
linux·运维·服务器
Irissgwe2 小时前
基础I/O
java·linux·前端
洛菡夕2 小时前
Linux系统安全
linux