網絡編程之IO模型與Epoll

一、IO模型

區分同步&異步,阻塞&非阻塞

  • 區分同步異步synchronous/asynchronous)。簡單來說,同步是一種可靠的有序運行機制,當我們進行同步操作時,後續的任務是等待當前調用返回,纔會進行下一步;而異步則相反,其他任務不需要等待當前調用返回,通常依靠事件、回調等機制來實現任務間次序關係。(最簡單:同步一次幹一件事,異步幹一件事的同事還可以幹別的事情,而且多用回調實現)

  • 區分阻塞非阻塞blocking/non-blocking)。用戶線程調用內核IO操作的方式:阻塞是指IO操作需要徹底完成後才返回到用戶空間;而非阻塞是指IO操作被調用後立即返回給用戶一個狀態值,無需等到IO操作徹底完成。

操作系統的IO過程,通常將其分爲兩個階段:

  • 1.等待遠程數據就緒。網卡會將數據報文傳給協議棧,封裝處理之後拷貝到內核緩衝區中(外部->內核態)
  • 2.將數據從內核緩衝區拷貝到進程中(內核態->用戶態)

根據這上面兩個事情就可以分爲四種IO模型:

1.同步阻塞I/O(Synchrohous, blocking I/O)

數據從外部介質到內核,從內核到用戶進程,每一步都是同步阻塞式的。


2.同步非阻塞I/O(Synchrohous, non-blocking I/O)

在非阻塞IO模型中,數據從外部到內核雖然不是阻塞的,但用戶線程需要不斷地詢問內核數據是否就緒,也就說非阻塞IO不會交出CPU,而會一直佔用CPU。


3.I/O多路複用(I/O Multiplexing)

linux中常見的select和epoll模型就是這種,雖然兩個階段都阻塞,但使用select以後可以在一個線程內同時處理多個socket的IO請求。用戶可以註冊多個socket,然後不斷地調用select讀取被激活的socket,即可達到在同一個線程內同時處理多個IO請求的目的。而在同步阻塞模型中,必須通過多線程的方式才能達到這個目的。(Java的NIO也是採用此種實現機制)

4.異步I/O(Asynchronous I/O)

兩個進程都是異步非阻塞的,完成後內核會給用戶進程發送一個signal,告訴它read操作完成了。


二、IO多路複用之Select/Poll和Epoll

Linux的內核將所有的外部設備都看作是一個文件來操作。對一個文件的操作會調用內核提供的系統命令,然後返回一個file descriptor(fd,文件描述符)。而對一個socket的讀寫也會有相應描述符,稱socketfd(socket描述符),描述符是一個數字,它指向內核中的一個結構體。

select,poll,epoll都是IO多路複用的機制。I/O多路複用就是通過一種機制,一個進程可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因爲他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說把數據從內核拷貝到用戶空間是阻塞的,而異步I/O則無需自己負責進行讀寫,異步I/O的實現會負責把數據從內核拷貝到用戶空間與多進程和多線程技術相比,I/O多路複用技術的最大優勢是系統開銷小,系統不必創建進程/線程,也不必維護這些進程/線程,從而大大減小了系統的開銷。

Epoll的工作原理如下:

主要過程:把socket放到epoll文件系統裏file對象對應的紅黑樹上,紅黑樹中是否存在,立即返回,不存在則添加到紅黑樹上。 所有添加到epoll中的事件都會與設備(網卡)驅動程序建立回調關係,也就是說,當相應的事件發生時會調用這個回調方法。這個回調方法在內核中叫ep_poll_callback,它會將發生的事件添加到rdlist雙鏈表中。

和select的區別也就在這裏:select/poll每次調用都要傳遞所要監控的所有fd給select/poll系統調用,這意味着每次調用都要將fd列表從用戶態拷貝到內核態,當fd數目很多時,這會造成低效。

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