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/zh-tw/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

發表回復

登錄後才能評論