Linux Epoll介紹和程序實例

裝載自:http://blog.csdn.net/sparkliang/archive/2009/11/05/4770655.aspx

 

 

 

Linux Epoll介紹和程序實例

1. Epoll 是何方神聖?

Epoll 可是當前在 Linux 下開發大規模併發網絡程序的熱門人選, Epoll  Linux2.6 內核中正式引入,和 select 相似,其實都 I/O 多路複用技術而已 ,並沒有什麼神祕的。

其實在 Linux 下設計併發網絡程序,向來不缺少方法,比如典型的 Apache 模型( Process Per Connection ,簡稱 PPC ), TPC  Thread Per Connection )模型,以及 select 模型和 poll 模型,那爲何還要再引入 Epoll 這個東東呢?那還是有得說說的 

2. 常用模型的缺點

如果不擺出來其他模型的缺點,怎麼能對比出 Epoll 的優點呢。

2.1 PPC/TPC 模型

這兩種模型思想類似,就是讓每一個到來的連接一邊自己做事去,別再來煩我 。只是 PPC 是爲它開了一個進程,而 TPC 開了一個線程。可是別煩我是有代價的,它要時間和空間啊,連接多了之後,那麼多的進程 / 線程切換,這開銷就上來了;因此這類模型能接受的最大連接數都不會高,一般在幾百個左右。

2.2 select 模型

1. 最大併發數限制,因爲一個進程所打開的 FD (文件描述符)是有限制的,由 FD_SETSIZE 設置,默認值是 1024/2048 ,因此 Select 模型的最大併發數就被相應限制了。自己改改這個 FD_SETSIZE ?想法雖好,可是先看看下面吧 

2. 效率問題, select 每次調用都會線性掃描全部的 FD 集合,這樣效率就會呈現線性下降,把 FD_SETSIZE 改大的後果就是,大家都慢慢來,什麼?都超時了??!!

3. 內核 / 用戶空間 內存拷貝問題,如何讓內核把 FD 消息通知給用戶空間呢?在這個問題上 select 採取了內存拷貝方法。

2.3 poll 模型

基本上效率和 select 是相同的, select 缺點的 2  3 它都沒有改掉。

3. Epoll 的提升

把其他模型逐個批判了一下,再來看看 Epoll 的改進之處吧,其實把 select 的缺點反過來那就是 Epoll 的優點了。

3.1. Epoll 沒有最大併發連接的限制,上限是最大可以打開文件的數目,這個數字一般遠大於 2048, 一般來說這個數目和系統內存關係很大 ,具體數目可以 cat /proc/sys/fs/file-max 察看。

3.2. 效率提升, Epoll 最大的優點就在於它只管你“活躍”的連接 ,而跟連接總數無關,因此在實際的網絡環境中, Epoll 的效率就會遠遠高於 select  poll 

3.3. 內存拷貝, Epoll 在這點上使用了“共享內存 ”,這個內存拷貝也省略了。

 

 

4. Epoll 爲什麼高效

Epoll 的高效和其數據結構的設計是密不可分的,這個下面就會提到。

首先回憶一下 select 模型,當有 I/O 事件到來時, select 通知應用程序有事件到了快去處理,而應用程序必須輪詢所有的 FD 集合,測試每個 FD 是否有事件發生,並處理事件;代碼像下面這樣:


int res = select(maxfd+1, &readfds, NULL, NULL, 120);

if (res > 0)

{

    for (int i = 0; i < MAX_CONNECTION; i++)

    {

        if (FD_ISSET(allConnection[i], &readfds))

        {

            handleEvent(allConnection[i]);

        }

    }

}

// if(res == 0) handle timeout, res < 0 handle error

 

Epoll 不僅會告訴應用程序有I/0 事件到來,還會告訴應用程序相關的信息,這些信息是應用程序填充的,因此根據這些信息應用程序就能直接定位到事件,而不必遍歷整個FD 集合。

int res = epoll_wait(epfd, events, 20, 120);

for (int i = 0; i < res;i++)

{

    handleEvent(events[n]);

}

5. Epoll 關鍵數據結構

前面提到 Epoll 速度快和其數據結構密不可分,其關鍵數據結構就是:

struct epoll_event {

    __uint32_t events;      // Epoll events

    epoll_data_t data;      // User data variable

};

typedef union epoll_data {

    void *ptr;

    int fd;

    __uint32_t u32;

    __uint64_t u64;

} epoll_data_t;

可見 epoll_data 是一個 union 結構體 , 藉助於它應用程序可以保存很多類型的信息 :fd 、指針等等。有了它,應用程序就可以直接定位目標了。

6. 使用 Epoll

既然 Epoll 相比 select 這麼好,那麼用起來如何呢?會不會很繁瑣啊  先看看下面的三個函數吧,就知道 Epoll 的易用了。

 

int epoll_create(int size);

生成一個 Epoll 專用的文件描述符,其實是申請一個內核空間,用來存放你想關注的 socket fd 上是否發生以及發生了什麼事件。 size 就是你在這個 Epoll fd 上能關注的最大 socket fd 數,大小自定,只要內存足夠。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );

控制某個 Epoll 文件描述符上的事件:註冊、修改、刪除。其中參數 epfd  epoll_create() 創建 Epoll 專用的文件描述符。相對於 select 模型中的 FD_SET  FD_CLR 宏。

int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);

等待 I/O 事件的發生;參數說明:

epfd:  epoll_create() 生成的 Epoll 專用的文件描述符;

epoll_event: 用於回傳代處理事件的數組;

maxevents: 每次能處理的事件數;

timeout: 等待 I/O 事件發生的超時值;

返回發生事件數。

相對於 select 模型中的 select 函數。

7. 例子程序

下面是一個簡單 Echo Server 的例子程序,麻雀雖小,五臟俱全,還包含了一個簡單的超時檢查機制,簡潔起見沒有做錯誤處理。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章