27.epoll(三)

一.回顾

建议先学上篇博客,再向下学习,上篇博客的链接如下:

https://blog.csdn.net/weixin_60668256/article/details/155077409?fromshare=blogdetail&sharetype=blogdetail&sharerId=155077409&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.IOService.hpp的sender()实现

cpp 复制代码
virtual void Sender() override
    {
        while(true)
        {
            ssize_t n = send(sockfd(),OutString().c_str(),OutString().size(),0);
            if(n > 0)
            {
                //成功
                DisCardOutString(n);//移除发送的n个字符串
            }
            else if(n == 0)
            {
                break;
            }
            else
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    //缓冲区写满了,下次再来写
                    break;
                }
                else if(errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }
        //本轮发送完了
        //1.outbuffer empty
        //2.发送缓冲区写满了 && outbuffer 没有empty
        //写条件不满足,我们要将sockfd的事件写入到epoll模型中
        if(!IsOutBufferEmpty())
        {
            //修改对sockfd的事件关心!  --  开启对写事件的关心
            GetOwner()->EnableReadWrite(sockfd(),true,true);
        }
        else
        {
            GetOwner()->EnableReadWrite(sockfd(),true,false);
        }
    }

我们要将给文件描述符的关心事件全部都进行更改

cpp 复制代码
void EnableReadWrite(int sockfd,bool readable,bool writeable)
    {
        if(IsConnectionExists(sockfd))
        {
            uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
           _connections[sockfd]->SetEvents(events);

           _epoller->Update(sockfd,_connections[sockfd]->GetEvents());
        }
    }
cpp 复制代码
void Ctrl(int sockfd,uint32_t events,int flag)
        {
            struct epoll_event ev;
            ev.events = events;
            ev.data.fd = sockfd;
            int n = epoll_ctl(_epfd,flag,sockfd,&ev);
            if(n < 0)
            {
                LOG(LogLevel::WARNING) << "epoll_ctl error";
            }
        }
        void Add(int sockfd,uint32_t events)
        {
            Ctrl(sockfd,events,EPOLL_CTL_ADD);
        }
        void Update(int sockfd,uint32_t events)
        {
            Ctrl(sockfd,events,EPOLL_CTL_MOD);
        }

我可以用以前的客户端来向我们的服务器进行发起请求

三.异常处理

cpp 复制代码
virtual void Excepter()override
    {
        //IO读取时,所有的异常处理,全部都会转化为这个函数
        //打印日志,差错处理,关闭连接,Reactor移除connection,删除epoll模型中的节点
        LOG(LogLevel::INFO) << "客户端可能结束,进行异常处理: " << sockfd();
        GetOwner()->DelConnection(sockfd());
    }

四.后续扩展设计

每次发送消息和接收消息,都进行更新时间(这样我们就能做连接管理了)

五.多进程和多线程

1.方案一(多进程)

由一个Master创建多个子进程,然后用管道进行通信

有任何一个请求到了,Master进程不做任何的处理,直接通知子进程

epoll啥都能进行关心(包括管道)

2.方案二(多线程)

我们使用管道,既可以唤醒对应的Reactor,也可以唤醒对应的条件变量

3.方案三(事件驱动)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/eventfd.h>

int main() {
    int efd = eventfd(0, EFD_CLOEXEC);  // 创建 eventfd
    if (efd == -1) {
        perror("eventfd");
        return 1;
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        return 1;
    }

    if (pid == 0) {  // 子进程
        uint64_t value;
        read(efd, &value, sizeof(value));  // 从 eventfd 读取事件
        printf("Child process received event\n");
        close(efd);
        return 0;
    } else {  // 父进程
        uint64_t value = 1;
        write(efd, &value, sizeof(value));  // 向 eventfd 写入事件
        printf("Parent process sent event\n");
        wait(NULL);  // 等待子进程结束
        close(efd);
        return 0;
    }
}

我们这里使用的是用户空间用于我们文件描述符的传递,事件通知用我们对应的eventfd

相关推荐
亚空间仓鼠7 分钟前
OpenEuler系统常用服务(五)
linux·运维·服务器·网络
聊点儿技术12 分钟前
CDN调度失准导致跨省流量浪费?在GSLB层用IP归属地查询实现精准就近接入
网络·ip·ip归属地查询·ip地址查询·ip离线库·cdn调度
EAIReport17 分钟前
国外网站数据批量采集技术实现路径
开发语言·python
超绝振刀怪18 分钟前
【C++可变模板参数】
开发语言·c++·可变模板参数
咸鱼嵌入式27 分钟前
【AutoSAR】详解PDUR模块
网络
Freak嵌入式29 分钟前
MicroPython LVGL基础知识和概念:时序与动态效果
开发语言·python·github·php·gui·lvgl·micropython
AI成长日志1 小时前
【AI原生开发实战】1.2 传统开发 vs AI原生开发:思维转变与架构差异
服务器·架构·ai-native
戮戮1 小时前
Spring Cloud Gateway 零拷贝参数校验:一种高性能网关架构实践
java·网络·架构·gateway
2501_933329551 小时前
企业媒体发布与舆情管理实战:Infoseek舆情系统技术架构与落地解析
大数据·开发语言·人工智能·数据库开发