fastlio2源码解读

一、IO多路复用

/**
 * @brief 封装select的IO多路复用函数
 */
void FIO::Select(int timeoutMs)
{
    struct timeval timeout;
    timeout.tv_sec = timeoutMs / 1000;
    timeout.tv_usec = (timeoutMs % 1000) * 1000;
    fd_set rfds, wfds;
    FD_ZERO(&rfds);
    FD_ZERO(&wfds);
    int max_fd = -1;
    for (auto& fd : rset_)
    {
        FD_SET(fd, &rfds);
        max_fd = std::max(max_fd, fd);
    }
    for (auto& fd : wset_)
    {
        FD_SET(fd, &wfds);
        max_fd = std::max(max_fd, fd);
    }
    int nready = select(max_fd + 1, &rfds, &wfds, nullptr, timeoutMs == -1 ? nullptr : &timeout);
    if(nready < 0)
    {
        if(errno == EINTR) return; //中断
        perror("select");
        abort();
    }
    if(FD_ISSET(pipe_fd_[0], &rfds)) ReadEvent(); //读事件
    if(nready <= 0) return;
    for (auto& fd : rset_)
    {
        if(FD_ISSET(fd, &rfds)) readCallback_(fd);
    }
    for (auto& fd : wset_)
    {
        if(FD_ISSET(fd, &wfds)) writeCallback_(fd);
    }
}

fastlio2使用IO多路复用技术,代码中提供了封装select的IO多路复用函数Select。Select可以同时得到读写事件的通知。在Select函数中,先对读写事件分别进行了set,取得当前连接数最大的fd,然后在select内部会阻塞至少timeoutSecs秒等待有事件发生。如果一直等下去,但没有任何一个事件发生,那么就会超时。

二、连接管理

/**
 * @brief 为连接设置回调函数,然后以此维持连接的生命周期
 */
void Connection::SetCallback(const closure_t& read_cb, const closure_t& write_cb, const callback_t& error_cb, bool use_mutex)
{
    read_cb_ = read_cb;
    write_cb_ = write_cb;
    error_cb_ = error_cb;
    events_ |= kPollIn;
    if (write_cb_) events_ |= kPollOut;
    if (use_mutex) mutex_.lock();
    conn_stats_.active = true;
    if (use_mutex) mutex_.unlock();
    loop_->AddEvents(fd_, events_);
}

Connect是fastlio2中重要的连接类,其录了连接的流程和生命周期的维护。代码中SetCallback函数会传入三个回调函数,并且设置读事件,在传入的写事件回调函数不为空时,同时设置读写两个事件。

三、事件循环

/**
 * @brief 注册新事件
 */
void EventLoop::AddEvents(int fd, int events, int clear_events)
{
    struct epoll_event event;
    event.data.fd = fd;
    event.events = events | EPOLLET | EPOLLERR | EPOLLHUP;
    if(clear_events != 0) event.events |= clear_events;
    if(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event) < 0)
    {
        perror("eventloop epol_ctl add failed");
        abort();
    }
    else
    {
        total_events_++;
    }
}

/**
 * @brief 删除事件
 */
void EventLoop::RemoveEvents(int fd)
{
    if(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr) < 0)
    {
        perror("eventloop epol_ctl del failed");
        abort();
    }
    else
    {
        total_events_--;
    }
}

EventLoop作为fastlio2的核心之一,负责事件循环和事件的注册和删除。代码中AddEvents函数通过epoll_ctl函数注册事件,只有在注册成功后,total_events_计数器才会加一。RemoveEvents函数则是从epoll中删除事件,并在删除成功后将计数器减一。

四、信号处理

/**
 * @brief 注册信号处理函数
 */
void FSignal::Register(int signo, const signal_callback_t& callback)
{
    sa_.sa_handler = handler;
    sigfillset(&sa_.sa_mask);
    sa_.sa_flags = 0;
    sigaction(signo, &sa_, nullptr);
}

/**
 * @brief 处理信号中断
 */
void FSignal::handler(int sig)
{
    void* array[1024];
    auto size = backtrace(array, 1024);
    fprintf(stderr, "signal %d caught:\n", sig);
    backtrace_symbols_fd(array, size, STDERR_FILENO);
    _exit(1);
}

FSignal类利用了*nu_signal.h*库处理程序的信号。Register函数直接调用了sigaction函数,通过注册信号处理函数来处理特定的信号。handler函数针对了信号的中断,当接收到SIGABRT信号时,程序会打印出当前函数调用栈的dump,然后终止程序的执行。

五、缓存池

/**
 * @brief 读取一行请求(只限HTTP协议头)
 */
int ByteBuffer::ReadHttpLine(char* buf, int maxlen)
{
    int begin_pos = pos_;
    char c = 0;
    int len = 0;
    while (pos_ < limit_ && len  begin_pos ? len : -1;
}

ByteBuffer负责对读取的数据进行缓存,用于最大化的减少IO次数。代码中,ReadHttpLine函数从缓存中读取标准的HTTP协议头,读取到socket的下一个请求头后,循环立即退出。如果在maxlen的最大长度内没有定位到HTTP头,则返回-1。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/196015.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-03 09:51
下一篇 2024-12-03 09:52

相关推荐

  • 云智直聘 源码分析

    本文将会对云智直聘的源码进行分析,包括前端页面和后端代码,帮助读者了解其架构、技术实现以及对一些常见的问题进行解决。通过本文的阅读,读者将会了解到云智直聘的特点、优势以及不足之处,…

    编程 2025-04-29
  • Python网站源码解析

    本文将从多个方面对Python网站源码进行详细解析,包括搭建网站、数据处理、安全性等内容。 一、搭建网站 Python是一种高级编程语言,适用于多种领域。它也可以用于搭建网站。最常…

    编程 2025-04-28
  • 源码是什么

    源码是一段计算机程序的原始代码,它是程序员所编写的可读性高、理解性强的文本。在计算机中,源码是指编写的程序代码,这些代码按照一定规则排列,被计算机识别并执行。 一、源码的组成 源码…

    编程 2025-04-27
  • Go源码阅读

    Go语言是Google推出的一门静态类型、编译型、并发型、语法简单的编程语言。它因具有简洁高效,内置GC等优秀特性,被越来越多的开发者所钟爱。在这篇文章中,我们将介绍如何从多个方面…

    编程 2025-04-27
  • Python怎么看源码

    本文将从以下几个方面详细介绍Python如何看源码,帮助读者更好地了解Python。 一、查看Python版本 在查看Python源码之前,首先需要确认Python版本。可以在命令…

    编程 2025-04-27
  • 源码审计面试题用法介绍

    在进行源码审计面试时,可能会遇到各种类型的问题,本文将以实例为基础,从多个方面对源码审计面试题进行详细阐述。 一、SQL注入 SQL注入是常见的一种攻击方式,攻击者通过在输入的参数…

    编程 2025-04-27
  • 对3ue源码的多方面阐述

    一、3ue源码简述 3ue是一款基于Vue.js开发的富文本编辑器,支持图片上传、粘贴、表格、代码块等多种功能,具有轻量、可定制、易扩展的特点。下面我们将从多个方面对3ue源码进行…

    编程 2025-04-22
  • 全面解析ptable:从使用到源码分析

    ptable是一个轻量级的DOM操作插件,主要用于表格的操作和功能增强。它的使用非常灵活,支持多种操作方式,包括添加、删除、修改、排序、筛选等,可以大大提高表格的效率和易用性。 一…

    编程 2025-04-22
  • 深入分析Redis源码

    一、Redis简介 Redis是一个开源的内存数据结构存储系统,可以用作数据库、缓存、消息队列等。Redis支持多种数据类型,包括字符串、哈希、列表、集合等。Redis基于C语言进…

    编程 2025-04-12
  • JDK源码阅读详解

    一、jdk源码阅读顺序 首先,在开始阅读JDK源码之前,需要按照正确的顺序来阅读代码。一般建议按照以下顺序进行阅读: 1. 先从Java SE的API入手,了解它提供了哪些功能,及…

    编程 2025-04-12

发表回复

登录后才能评论