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

相关推荐
瑞码空间4 分钟前
Python爬虫进阶实战笔记
开发语言·python·计算机·python爬虫
16月6日-晴12 分钟前
Java面向对象进阶—static
java·开发语言
爱跳舞的烤冷面13 分钟前
自学嵌入式第16天(数据结构篇--链表进阶操作)
开发语言
持敬chijing26 分钟前
PHP开发-环境搭建-安装phpstudy-vscode工具
开发语言·vscode·php
charlie1145141911 小时前
Cinux · 第一次跳进 Ring 3:用户态与特权隔离
开发语言·c++·操作系统·开源项目
2401_834636991 小时前
从零吃透 K8s 网络:ServiceIngressMetalLB 实操手册
网络·容器·kubernetes
躺不平的理查德1 小时前
Windows C++ 第三方库使用流程备忘录--OpenCV
开发语言·c++
菜冻鱼1 小时前
Python-sklearn-评估指标
开发语言·人工智能·python·机器学习·numpy·pandas·sklearn
for_ever_love__2 小时前
python基础语法学习: 变量, 输入输出, 运算符
网络·python·学习
你挚爱的强哥2 小时前
【exportExcel】单纯靠js不用任何其他第三方插件导出xls格式文件
开发语言·javascript·ecmascript