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

相关推荐
wanhengidc8 小时前
云手机 高振畅玩不踩坑
运维·服务器·安全·web安全·智能手机
有谁看见我的剑了?8 小时前
linux 添加硬盘后系统识别不到硬盘处理
linux·运维·服务器
易连EDI—EasyLink8 小时前
易连EDI–EasyLink实现OCR智能数据采集
网络·人工智能·安全·汽车·ocr·edi
@insist1238 小时前
信息安全工程师考点精讲:身份认证核心原理与分类体系(上篇)
大数据·网络·分类·信息安全工程师·软件水平考试
九转成圣9 小时前
Java 性能优化实战:如何将海量扁平数据高效转化为类目字典树?
java·开发语言·json
SmartRadio9 小时前
ESP32-S3 双模式切换实现:兼顾手机_路由器连接与WiFi长距离通信
开发语言·网络·智能手机·esp32·长距离wifi
laowangpython9 小时前
Rust 入门:GitHub 热门内存安全编程语言
开发语言·其他·rust·github
我叫汪枫9 小时前
在后台管理系统中,如何递归和选择保留的思路来过滤菜单
开发语言·javascript·node.js·ecmascript
_.Switch9 小时前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
软件技术NINI9 小时前
webkit简介及工作流程
开发语言·前端·javascript·udp·ecmascript·webkit·yarn