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

相关推荐
Danileaf_Guo4 小时前
256台H100服务器算力中心的带外管理网络建设方案
运维·服务器
橘子真甜~5 小时前
C/C++ Linux网络编程15 - 网络层IP协议
linux·网络·c++·网络协议·tcp/ip·计算机网络·网络层
小浣熊熊熊熊熊熊熊丶5 小时前
《Effective Java》第25条:限制源文件为单个顶级类
java·开发语言·effective java
云老大TG:@yunlaoda3605 小时前
华为云国际站代理商IMS主要有什么作用呢?
tcp/ip·华为云·云计算·负载均衡
啃火龙果的兔子5 小时前
JDK 安装配置
java·开发语言
星哥说事5 小时前
应用程序监控:Java 与 Web 应用的实践
java·开发语言
Allen正心正念20256 小时前
网络编程与通讯协议综合解析
网络
等....6 小时前
Miniconda使用
开发语言·python
zfj3216 小时前
go为什么设计成源码依赖,而不是二进制依赖
开发语言·后端·golang
醇氧6 小时前
org.jetbrains.annotations的@Nullable 学习
java·开发语言·学习·intellij-idea