早期BIO ,blockingIO,阻塞IO。Linux下一切皆文件,socket即讀文件描述符(fd)。當建立多個連接時,如下圖。
例如fd 8 的client連接一直沒返回,導致 read fd8會進行阻塞,一直等待返回。read fd9連接無法進行處理。
由於BIO 導致阻塞,進而演變成NIO。
開始進入NONBLOCK時代,非阻塞。還是多個連接。
非阻塞了,當多個連接來時,進行while 循環,循環調用 fd8 fd9 read,判斷有沒有返回,有就處理,沒有繼續循環。
解決了BIO的問題,但是問題又來了。如果有1000個連接,就需要不斷地循環1000,從fd1 到fd1000,效率多低。
進而演變內核發展,提供 select 調用。 select接口開始,不用做循環了,直接把fd1到fd1000全部傳給select,進行監控,直到有一個或多個的返回,將有返回的fd描述符傳給線程去read對應的描述符返回信息。即多路複用NIO時代
雖然進入了多路複用,但是過程很複雜,需要調用select,然後根據返回再去read。尤其是1000個描述符需要從用戶態拷貝給select。
內核發展出epoll,用戶空間可以調用epoll的create時,內核返回一個epfd(epoll的描述符),當用戶空間有一個連接進來後,將連接交給epoll描述符,同時調用epoll的wait(),epoll會準備一個共享空間mmap,只需要維護一個紅黑樹,連接都放到紅黑樹裏面。共享空間裏面增刪改由內核完成,用戶空間和內核雙方都可以查詢。當共享空間有連接返回後,wait()就可以返回了,從阻塞變成不阻塞,取出到達的那些描述符,單獨去read。
相當於用戶空間註冊一個連接到內核的epoll共享空間中,連接有返回後進行回調,由內核通知用戶空間,再去read描述符。
mmap:共享空間。由內核實現。相當於用戶態和內核態之間出現了一個共享空間。