linux epoll 開發指南

2021-08-16 05:51:47 字數 3353 閱讀 3342

原文:

關於epoll的問題很早就像寫文章講講自己的看法,但是由於ffrpc一直沒有完工,所以也就拖下來了。epoll主要在伺服器程式設計中使用,本文主要**伺服器程式中epoll的使用技巧。epoll一般和非同步io結合使用,故本文討論基於以下應用場合:

epoll是為非同步io操作而設計的,epoll中io事件被分為read事件和write事件,如果大家對於linux的驅動模組或者linux io 模型有接觸的話,就會理解起來更容易。linux中io操作被抽象為read、write、close、ctrl幾個操作,所以epoll只提供read、write、error事件,是和linux的io模型是統一的。

為什麼要了解epoll的io模型呢,本文認為,某些情況下epoll操作的**的複雜性是由於**中的模型(或者類設計)與epoll io模型不匹配造成的。換句話說,如果我們的編碼模型和epoll io模型匹配,那麼非阻塞socket的編碼就會很簡單、清晰。

按照epoll模型構建的類關係為:

//! 檔案描述符相關介面

typedef intsocket_fd_t;

classfd_i

virtual socket_fd_t socket() = 0;

virtual int handle_epoll_read() = 0;

virtual int handle_epoll_write() = 0;

virtual int handle_epoll_del() = 0;

virtual void close() = 0;

};intepoll_impl_t::event_loop()

for (i = 0; i < nfds; ++i)

//! 刪除那些已經出現error的socket 物件

fd_del_callback();

continue;

}if (cur_ev.events & (epollin |epollpri))

if(cur_ev.events &epollout)

if (cur_ev.events & (epollerr |epollhup))

}}while(nfds >= 0);

return 0;

}

先簡單比較一下level trigger 和 edge trigger 模式的不同。

讓我們換乙個角度來理解et模式,事實上,epoll的et模式其實就是socket io完全狀態機。

當socket由不可讀變成可讀時,epoll的et模式返回read 事件。對於read 事件,開發者需要保證把讀取緩衝區資料全部讀出,man epoll可知:

示例**

需要讀者注意的是,socket模式是可寫的,因為傳送緩衝區初始時空的。故應用層有資料要傳送時,直接呼叫write系統呼叫傳送資料,若write系統呼叫返回ewouldblock則表示socket變為不可寫,或者write系統呼叫返回的數值小於傳入的buffer引數的大小,這時需要把未傳送的資料暫存在應用層待傳送列表中,等待epoll返回write事件,再繼續傳送應用層待傳送列表中的資料,同樣若應用層待傳送列表中的資料沒有一次性發完,那麼繼續等待epoll返回write事件,如此迴圈往復。所以可以反推得到如下結論,若應用層待傳送列表有資料,則該socket一定是不可寫狀態,那麼這時候要傳送新資料直接追加到待傳送列表中。若待傳送列表為空,則表示socket為可寫狀態,則可以直接呼叫write系統呼叫傳送資料。總結如下:

示例**:

void socket_impl_t::send_impl(const string&src_buff_)

//! socket buff is full, cache the data

if (false ==m_send_buffer.empty())

stringleft_buff;

int ret =do_send(buff_, left_buff);

if (ret < 0)

else if (ret > 0)

else

}intsocket_impl_t:: handle_epoll_write ()

doelse if (ret > 0)

else

} while (false ==m_send_buffer.empty());

m_sc->handle_write_completed(this);

return 0;

}

lt模式主要是讀操作比較簡單,但是對於et模式並沒有優勢,因為將讀取緩衝區資料全部讀出並不是難事。而write操作,et模式則流程非常的清晰,按照完全狀態機來理解和實現就變得非常容易。而lt模式的write操作則複雜多了,要頻繁的維護epoll的wail列表。

在**編寫時,把epoll et當成狀態機,當socket被建立完成(accept和connect系統呼叫返回的socket)時加入到epoll列表,之後就不用在從中刪除了。為什麼呢?man epoll中的faq告訴我們,當socket被close掉後,其自動從epoll中刪除。對於監聽socket簡單說幾點注意事項:

示例**:

intacceptor_impl_t::handle_epoll_read()

else if (errno == eintr || errno == emfile || errno == econnaborted || errno == enfile ||errno == eperm || errno == enobufs || errno ==enomem)

perror("accept");

return -1;

}socket_i* socket =create_socket(new_fd);

socket->open();

} while (true);

return 0;

}

github :

ffrpc 介紹:

Django Web開發指南

國內第一本django圖書 django web開發指南 歡迎使用django 歡迎來到django的世界,很高興能和你一起進行這趟旅程。你會發現有了這個強大的web框架,做每件事情都變得便捷起來 從設計開發新應用到不用大刀闊斧地修改 就能為現有 提供新的特性和功能。關於本書 市面上已經有了一些講解...

SQL Server 開發指南

sql server 資料庫設計 一 資料庫設計的必要性 二 什麼是資料庫設計 三 資料庫設計的重要 四 資料模型 實體 關係 e r 資料模型 實體 entity 屬性 attribute 關係 relationship 五 資料庫設計步驟 1 需求分析階段 2 概要設計階段 3 詳細設計階段 六...

shell 開發指南

語法 釋義使用示例 bash source 0 取得當前執行的shell檔案所在的路徑 context dirname 上一條指令執行完的退出狀態.0為成功,非0為失敗.if eq 0 then 基本結構 if 條件語句 then 執行語句1 else 執行語句2 fi注意條件語句外有 兩種形式 常...