Linux的內核將全部外部設備都看作一個文件來操做,對一個文件的讀寫操做會調用內核提供的系統命令,返回一個file descriptor(fd,文件描述符 )。而對一個socket的讀寫也會有相應的描述符,稱爲socketfd(socket描述符),描述符就是一個數字,它指向內核中的一個結構體(文件路徑,數據區等一些屬性)。程序員
根據UNIX網絡編程對I/O模型的分類,UNIX提供了5種I/O模型,分別以下:編程
阻塞I/O模型:最經常使用的I/O模型就是阻塞I/O模型,缺省情形下,全部文件操做都是阻塞的。咱們以套接字接口爲例來說解此模型。在進程空間中調用recvfrom,其系統調用直到數據包到達且被複制到應用進程的緩衝區中或者發生錯誤時才返回,在此期間一直會等待,進程在從調用recvfrom開始到它返回的整段時間內都是被阻塞的,所以被稱爲阻塞I/O模型。網絡
非阻塞I/O模型:rcvfrom從應用層到內核的時候,若是該緩衝區沒有數據的話,就直接返回一個EWOULDBLOCK錯誤,通常都對非阻塞I/O模型進行輪詢檢查這個狀態,看內核是否是有數據到來。異步
I/O複用模型:Linux提供select/poll(I/O複用模型會用到select或者poll函數,這兩個函數也會使進程阻塞,可是和阻塞I/O所不一樣的是,這兩個函數能夠同時阻塞多個I/O操做。並且能夠同時對多個讀操做,多個寫操做的I/O函數進行檢測,直到有數據可讀或可寫時,才真正調用I/O操做函數),進程經過將一個或多個fd傳遞給select或poll系統調用,阻塞在select操做上,這樣select/poll能夠幫咱們偵測多fd是否處於就緒狀態。select/poll是順序掃描fd是否就緒,並且支持的fd數量有限,所以它的使用受到了一些制約。Linux還提供了一個epoll系統調用,epoll使用基於事件驅動方式代替順序掃描,所以性能更高。當有fd就緒時,當即回調函數rollback。socket
信號驅動I/O模型:首先開啓套接口信號驅動I/O功能,並經過系統調用sigaction執行一個信號處理函數(此係統調用當即返回,進程繼續工做,它是非阻塞的)。當數據準備就緒時,就爲該進程生成一個SIGIO信號,經過信號回調通知應用程序調用recvfrom來讀取數據,並通知主循環函數處理數據。函數
異步I/O:告知內核啓動某個操做,並讓內核在整個操做完成後(包括將數據從內核複製到用戶本身的緩衝區)通知咱們。這種模型與信號驅動模型的主要區別是:信號驅動I/O由內核通知咱們什麼時候能夠開始一個I/O操做;異步I/O模型由內核通知咱們I/O操做什麼時候已經完成。性能
若是想要了解更多的UNIX系統網絡編程知識,能夠閱讀《UNIX網絡編程》,裏面有很是詳細的原理和API介紹。對於大多數Java程序員來講,不須要了解網絡編程的底層細節,你們只須要有個概念,知道對於操做系統而言,底層是支持異步I/O通訊的,只不過在很長一段時間Java並無提供異步I/O通訊的類庫,致使不少原生的Java程序員對這塊兒比較陌生。當你瞭解了網絡編程的基礎知識後,理解Java的NIO類庫就會更加容易一些。
spa