導航:首頁 > 操作系統 > linuxio模型

linuxio模型

發布時間:2022-10-09 05:39:23

⑴ 為什麼linux中監聽套接字時最大能監聽多少套接字

linux下,拋開性能上的影響,程序監聽套接字的數量限制主要幾個方面:

1:操作系統方面限制是句柄數量的限制,也就是65535個可用句柄去掉預先保留的,大概在5萬個左右,注意文件句柄和套接字句柄是共用的,都在這65535個裡面。

2:進程方面的限制,linux系統對單個進程的默認打開句柄數量限制是1024,考慮到文件操作也會佔用句柄,可用於socket監聽的句柄大概1000個,這個限制可以修改,不同linux版本可能有點不一樣,centos是通過命令 ulimit -n 的方式去修改,要改成10240,就是

3:IO模型的限制,select模型的限制是1024,個,epoll是無限制的,完全根據上面2個的最大值。

⑵ 什麼是IO模塊

I/O 模塊可分為離散、模擬和特殊模塊等多種類型,這些模塊都可以安裝在帶有多個插槽的導軌或者機架上,每個模塊插人其中一個插槽。導軌或者機架具有不同規格,插槽數分為4、8、12 不等。一般情況下,電源模塊插在第一插槽內,編號為0,PLC插在第二插槽內,各種類型的輸入輸出模塊插在其餘插槽內。I/O模塊導軌的背面安裝帶有連接器的印製電路板,可以將插入I/O模塊的各插槽連接起來,插槽的上下邊可以使插入的模塊排成一條直線。

(2)linuxio模型擴展閱讀:

IO模塊的分類:

1、RIO-8100-4DI4DO:4路開關量輸入/4路計數器,4路繼電器輸出。

2、RIO-8100-4DI:4路開關量輸入/4路計數器

3、RIO-8100-4DO:4路繼電器輸出。

4、RIO-8100-6DO:6路繼電器輸出。

5、RIO-8100-2DI5DO:2路開關量輸入/2路計數器,5路繼電器輸出。

RIO-8100系列遠程採集與控制模塊,採用 RS232、RS485通信模式與上位進行數據交互。

⑶ Linux中非同步IO模型有哪些

1)阻塞I/O(blocking I/O)
2)非阻塞I/O (nonblocking I/O)
3) I/O復用(select 和poll) (I/O multiplexing)
4)信號驅動I/O (signal driven I/O (SIGIO))
5)非同步I/O (asynchronous I/O (the POSIX aio_functions))
其中前4種都是同步,最後一種才是非同步。

⑷ Linux開發,使用多線程還是用IO復用select/epoll

多線程和用select/epoll是沒有關聯的,在select和epoll模型里也可以使用多線程進行io處理,select/epoll
的出現是為了解決一個線程對應一個請求時阻塞線程的問題,基於epoll的事件模型,解決了線程的阻塞問題即一個線程可以為多個請求服務

⑸ IO模型及select,poll,epoll和kqueue的區別

(一)首先,介紹幾種常見的I/O模型及其區別,如下:
blocking I/O
nonblocking I/O
I/O multiplexing (select and poll)
signal driven I/O (SIGIO)
asynchronous I/O (the POSIX aio_functions)—————非同步IO模型最大的特點是 完成後發回通知。
阻塞與否,取決於實現IO交換的方式。
非同步阻塞是基於select,select函數本身的實現方式是阻塞的,而採用select函數有個好處就是它可以同時監聽多個文件句柄.
非同步非阻塞直接在完成後通知,用戶進程只需要發起一個IO操作然後立即返回,等IO操作真正的完成以後,應用程序會得到IO操作完成的通知,此時用戶進程只需要對數據進行處理就好了,不需要進行實際的IO讀寫操作,因為真正的IO讀取或者寫入操作已經由內核完成了。

1 blocking I/O
這個不用多解釋吧,阻塞套接字。下圖是它調用過程的圖示:

重點解釋下上圖,下面例子都會講到。首先application調用 recvfrom()轉入kernel,注意kernel有2個過程,wait for data和 data from kernel to user。直到最後 complete後,recvfrom()才返回。此過程一直是阻塞的。

2 nonblocking I/O:
與blocking I/O對立的,非阻塞套接字,調用過程圖如下:

可以看見,如果直接操作它,那就是個輪詢。。直到內核緩沖區有數據。

3 I/O multiplexing (select and poll)
最常見的I/O復用模型,select。

select先阻塞,有活動套接字才返回。與blocking I/O相比,select會有兩次系統調用,但是select能處理多個套接字。

4 signal driven I/O (SIGIO)
只有UNIX系統支持,感興趣的課查閱相關資料

與I/O multiplexing (select and poll)相比,它的優勢是,免去了select的阻塞與輪詢,當有活躍套接字時,由注冊的handler處理。

5 asynchronous I/O (the POSIX aio_functions)
很少有*nix系統支持,windows的IOCP則是此模型

完全非同步的I/O復用機制,因為縱觀上面其它四種模型,至少都會在由kernel data to appliction時阻塞。而該模型是當完成後才通知application,可見是純非同步的。好像只有windows的完成埠是這個模型,效率也很出色。
6 下面是以上五種模型的比較

可以看出,越往後,阻塞越少,理論上效率也是最優。
=====================分割線==================================
5種模型的比較比較清晰了,剩下的就是把select,epoll,iocp,kqueue按號入座那就OK了。
select和iocp分別對應第3種與第5種模型,那麼epoll與kqueue呢?其實也於select屬於同一種模型,只是更高級一些,可以看作有了第4種模型的某些特性,如callback機制。
為什麼epoll,kqueue比select高級?
答案是,他們無輪詢。因為他們用callback取代了。想想看,當套接字比較多的時候,每次select()都要通過遍歷FD_SETSIZE個Socket來完成調度,不管哪個Socket是活躍的,都遍歷一遍。這會浪費很多CPU時間。如果能給套接字注冊某個回調函數,當他們活躍時,自動完成相關操作,那就避免了輪詢,這正是epoll與kqueue做的。
windows or *nix (IOCP or kqueue/epoll)?

誠然,Windows的IOCP非常出色,目前很少有支持asynchronous I/O的系統,但是由於其系統本身的局限性,大型伺服器還是在UNIX下。而且正如上面所述,kqueue/epoll 與 IOCP相比,就是多了一層從內核數據到應用層的阻塞,從而不能算作asynchronous I/O類。但是,這層小小的阻塞無足輕重,kqueue與epoll已經做得很優秀了。
提供一致的介面,IO Design Patterns
實際上,不管是哪種模型,都可以抽象一層出來,提供一致的介面,廣為人知的有ACE,Libevent(基於reactor模式)這些,他們都是跨平台的,而且他們自動選擇最優的I/O復用機制,用戶只需調用介面即可。說到這里又得說說2個設計模式,Reactor and Proactor。見:Reactor模式--VS--Proactor模式。Libevent是Reactor模型,ACE提供Proactor模型。實際都是對各種I/O復用機制的封裝。
java nio包是什麼I/O機制?
現在可以確定,目前的java本質是select()模型,可以檢查/jre/bin/nio.dll得知。至於java伺服器為什麼效率還不錯。。我也不得而知,可能是設計得比較好吧。。-_-。
=====================分割線==================================
總結一些重點:
只有IOCP是asynchronous I/O,其他機制或多或少都會有一點阻塞。
select低效是因為每次它都需要輪詢。但低效也是相對的,視情況而定,也可通過良好的設計改善
epoll, kqueue、select是Reacor模式,IOCP是Proactor模式。
java nio包是select模型。。
(二)epoll 與select的區別

1. 使用多進程或者多線程,但是這種方法會造成程序的復雜,而且對與進程與線程的創建維護也需要很多的開銷。(Apache伺服器是用的子進程的方式,優點可以隔離用戶) (同步阻塞IO)

2.一種較好的方式為I/O多路轉接(I/O multiplexing)(貌似也翻譯多路復用),先構造一張有關描述符的列表(epoll中為隊列),然後調用一個函數,直到這些描述符中的一個准備好時才返回,返回時告訴進程哪些I/O就緒。select和epoll這兩個機制都是多路I/O機制的解決方案,select為POSIX標准中的,而epoll為Linux所特有的。

區別(epoll相對select優點)主要有三:
1.select的句柄數目受限,在linux/posix_types.h頭文件有這樣的聲明:#define __FD_SETSIZE 1024 表示select最多同時監聽1024個fd。而epoll沒有,它的限制是最大的打開文件句柄數目。

2.epoll的最大好處是不會隨著FD的數目增長而降低效率,在selec中採用輪詢處理,其中的數據結構類似一個數組的數據結構,而epoll是維護一個隊列,直接看隊列是不是空就可以了。epoll只會對"活躍"的socket進行操作---這是因為在內核實現中epoll是根據每個fd上面的callback函數實現的。那麼,只有"活躍"的socket才會主動的去調用 callback函數(把這個句柄加入隊列),其他idle狀態句柄則不會,在這點上,epoll實現了一個"偽"AIO。但是如果絕大部分的I/O都是「活躍的」,每個I/O埠使用率很高的話,epoll效率不一定比select高(可能是要維護隊列復雜)。

3.使用mmap加速內核與用戶空間的消息傳遞。無論是select,poll還是epoll都需要內核把FD消息通知給用戶空間,如何避免不必要的內存拷貝就很重要,在這點上,epoll是通過內核於用戶空間mmap同一塊內存實現的。

關於epoll工作模式ET,LT

epoll有兩種工作方式
ET:Edge Triggered,邊緣觸發。僅當狀態發生變化時才會通知,epoll_wait返回。換句話,就是對於一個事件,只通知一次。且只支持非阻塞的socket。
LT:Level Triggered,電平觸發(默認工作方式)。類似select/poll,只要還有沒有處理的事件就會一直通知,以LT方式調用epoll介面的時候,它就相當於一個速度比較快的poll.支持阻塞和不阻塞的socket。

三 Linux並發網路編程模型

1 Apache 模型,簡稱 PPC ( Process Per Connection ,):為每個連接分配一個進程。主機分配給每個連接的時間和空間上代價較大,並且隨著連接的增多,大量進程間切換開銷也增長了。很難應對大量的客戶並發連接。
2 TPC 模型( Thread Per Connection ):每個連接一個線程。和PCC類似。
3 select 模型:I/O多路復用技術。
.1 每個連接對應一個描述。select模型受限於 FD_SETSIZE即進程最大打開的描述符數linux2.6.35為1024,實際上linux每個進程所能打開描數字的個數僅受限於內存大小,然而在設計select的系統調用時,卻是參考FD_SETSIZE的值。可通過重新編譯內核更改此值,但不能根治此問題,對於百萬級的用戶連接請求 即便增加相應 進程數, 仍顯得杯水車薪呀。
.2select每次都會掃描一個文件描述符的集合,這個集合的大小是作為select第一個參數傳入的值。但是每個進程所能打開文件描述符若是增加了 ,掃描的效率也將減小。
.3內核到用戶空間,採用內存復制傳遞文件描述上發生的信息。
4 poll 模型:I/O多路復用技術。poll模型將不會受限於FD_SETSIZE,因為內核所掃描的文件 描述符集合的大小是由用戶指定的,即poll的第二個參數。但仍有掃描效率和內存拷貝問題。
5 pselect模型:I/O多路復用技術。同select。
6 epoll模型:
.1)無文件描述字大小限制僅與內存大小相關
.2)epoll返回時已經明確的知道哪個socket fd發生了什麼事件,不用像select那樣再一個個比對。
.3)內核到用戶空間採用共享內存方式,傳遞消息。
四 :FAQ
1、單個epoll並不能解決所有問題,特別是你的每個操作都比較費時的時候,因為epoll是串列處理的。 所以你有還是必要建立線程池來發揮更大的效能。
2、如果fd被注冊到兩個epoll中時,如果有時間發生則兩個epoll都會觸發事件。
3、如果注冊到epoll中的fd被關閉,則其會自動被清除出epoll監聽列表。
4、如果多個事件同時觸發epoll,則多個事件會被聯合在一起返回。
5、epoll_wait會一直監聽epollhup事件發生,所以其不需要添加到events中。
6、為了避免大數據量io時,et模式下只處理一個fd,其他fd被餓死的情況發生。linux建議可以在fd聯繫到的結構中增加ready位,然後epoll_wait觸發事件之後僅將其置位為ready模式,然後在下邊輪詢ready fd列表。

⑹ 同步與非同步,阻塞與非阻塞的區別,以及select,poll和epoll

非同步的概念和同步相對。
(1)當一個同步調用發出後,調用者要一直等待返回消息(結果)通知後,才能進行後續的執行;

(2)當一個非同步過程調用發出後,調用者不能立刻得到返回消息(結果)。實際處理這個調用的部件在完成後,通過 狀態、通知和回調 來通知調用者。

這里提到執行部件和調用者通過三種途徑返回結果:狀態、通知和回調。使用哪一種通知機制,依賴於執行部件的實現,除非執行部件提供多種選擇,否則不受調用者控制。

(A)阻塞調用是指調用結果返回之前,當前線程會被掛起,一直處於等待消息通知,不能夠執行其他業務

(B)非阻塞調用是指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回

場景比喻:
舉個例子,比如我去銀行辦理業務,可能會有兩種方式:

在上面的場景中,如果:
a)如果選擇排隊(同步),且排隊的時候什麼都不幹(線程被掛起,什麼都幹不了),是同步阻塞模型;
b)如果選擇排隊(同步),但是排隊的同時做與辦銀行業務無關的事情,比如抽煙,(線程沒有被掛起,還可以干一些其他的事),是同步非阻塞模型;
c)如果選擇拿個小票,做在位置上等著叫號(通知),但是坐在位置上什麼都不幹(線程被掛起,什麼都幹不了),這是非同步阻塞模型;
d)如果選擇那個小票,坐在位置上等著叫號(通知),但是坐著的同時還打電話談生意(線程沒有被掛起,還可以干其他事情),這是非同步非阻塞模型。

對這四種模型做一個總結:
1:同步阻塞模型,效率最低,即你專心排隊,什麼都不幹。
2:非同步阻塞,效率也非常低,即你拿著號等著被叫(通知),但是坐那什麼都不幹
3:同步非阻塞,效率其實也不高,因為涉及到線程的來回切換。即你在排隊的同時打電話或者抽煙,但是你必須時不時得在隊伍中挪動。程序需要在排隊和打電話這兩種動作之間來回切換,系統開銷可想而知。
4:非同步非阻塞,效率很高,你拿著小票在那坐著等叫號(通知)的同時,打電話談你的生意。

linux下幾個基本概念
1:用戶控制項和內核空間。 現代操作系統都是採用虛擬存儲器,在32位操作系統下,它的定址空間(虛擬存儲空間)為4G(2的32次方)。為了保證用戶進程補鞥呢直接操作內核,保證內核的安全,操作系統將虛擬空間劃分為兩部分,一部分為內核空間,一部分為用戶空間。對linux操作系統而言,將最高的1G位元組空間分給了內核使用,稱為內核空間,將較低的3G位元組的空間劃分為用戶空間。

2:進程切換很耗資源 ,為了控制進程的執行,內核必須有能力掛起正在cpu上運行的進程,並恢復以前掛起的某個進程的執行,這種行為叫進程的切換。每次切換,要保存上一個的上下文環境等等,總之記住進程切換很耗資源。

3:文件描述符 :文件描述符在形式上是一個非負整數。實際上,他是一個索引,指向內核為每個進程所維護的該進程打開文件的記錄表。當程序打開一個文件時,內核就會向進程返回一個非負整數的文件描述符。但是文件描述符一般在unix,linux系統中才講。

緩存IO ,大多數系統的默認IO操作都是緩存IO,在linux的緩存IO機制中,操作系統會將IO的數據緩存在系統的頁緩存(page cache)中,也就是說,數據會先被拷貝到操作系統內核的緩沖區,然後才會從操作系統內核的緩沖區拷貝到應用程序的地址空間。 緩存IO的缺點: 數據在傳輸過程中需要在應用程序和地址空間和內核進行多次數據拷貝操作,這種數據拷貝操作鎖帶來的cpu以及內存消耗是很大的。

LINUX的IO模型
網路IO的本質是socket的讀取。socket在linux系統被抽象為流,故對網路IO的操作可以理解為對流的操作。

對於一次IO訪問,比如以read操作為例, 數據會先被拷貝到操作系統內核的緩沖區,然後才會從內核緩沖區拷貝到進程的用戶層,即應用程序的地址空間 。故當一個read操作發生時,其實是經歷了兩個階段:
1:內核緩沖區的數據就位
2:數據從內核緩沖區拷貝到用戶程序地址空間

那麼具體到socket io的一次read操來說,這兩步分別是:
1:等待網路上的數據分組到達,然後復制到內核緩沖區中
2:數據從內核緩沖區拷貝到用戶程序的地址空間(緩沖區)

所以說 網路應用要處理的無非就兩個問題:網路IO和數據計算 ,一般來說網路io帶來的延遲影響比較大。

網路IO的模型大致有如下幾種:

熟悉不? 我們常說的select,poll和epoll就是屬於同步模型中多路復用IO的不同實現方法罷了。 下面分別對同步阻塞,同步不阻塞,同步io復用進行說明。

一:同步阻塞
它是最簡單也最常用的網路IO模型。linux下默認的socket都是blocking的。

從圖中可以看到,用戶進程調用recvfrom這個系統調用後,就處於阻塞狀態。然後kernel就開始了IO的第一個階段:數據准備。等第一個階段准備完成之後,kernel開始第二階段,將數據從內核緩沖區拷貝到用戶程序緩沖區(需要花費一定時間)。然後kernel返回結果(確切的說是recvfrom這個系統調用函數返回結果),用戶進程才結束blocking,重新運行起來。
總結 同步阻塞模型下,用戶程序在kernel執行io的兩個階段都被blocking住了 。但是優點也是因為這個,無延遲能及時返回數據,且程序模型簡單。

二:同步非阻塞
同步非阻塞就是隔一會瞄一下的輪詢方式。同步非阻塞模式其實是可以看做一小段一小段的同步阻塞模式。

三:IO多路復用
由於同步非阻塞方式需要不斷的輪詢,光輪詢就占據了很大一部分過程,且消耗cpu資源。而這個用戶進程可能不止對這個socket的read,可能還有對其他socket的read或者write操作,那人們就想到了一次輪詢的時候,不光只查詢詢一個socket fd,而是在一次輪詢下,查詢多個任務的socket fd的完成狀態,只要有任何一個任務完成,就去處理它。而且,輪詢人不是進程的用戶態,而是有人幫忙就好了。那麼這就是所謂的 IO多路復用 。總所周知的linux下的select,poll和epoll就是這么乾的。。。

selelct調用是內核級別的,selelct輪詢相比較同步非阻塞模式下的輪詢的區別為: 前者可以等待多個socket,能實現同時對多個IO埠的監聽 ,當其中任何一個socket數據准備好了,就返回可讀。 select或poll調用之後,會阻塞進程 ,與blocking IO 阻塞不用在於,此時的select不是等到所有socket數據達到再處理,而是某個socket數據就會返回給用戶進程來處理。
其實select這種相比較同步non-blocking的效果在單個任務的情況下可能還更差一些 ,因為這里調用了select和recvfrom兩個system call,而non-blocking只調用了一個recvfrom,但是 用select的優勢在於它可以同時處理多個socket fd

在io復用模型下,對於每一個socket,一般都設置成non-blocking,但是其實 整個用戶進程是一直被block的 ,只不過用戶process不是被socket IO給block住,而是被select這個函數block住的。

與多進程多線程技術相比,IO多路復用的最大優勢是系統開銷小。

一:select
select函數監視多個socket fs,直到有描述符就緒或者超時,函數返回。當select函數返回後,可以通過遍歷fdset,來找到就緒的描述符。select的基本流程為:

二:poll
poll本質上跟select沒有區別,它將用戶傳入的數組拷貝到內核空間,然後查詢每個fd的狀態,如果某個fd的狀態為就緒,則將此fd加入到等待隊列中並繼續遍歷。如果遍歷完所有的fd後發現沒有就緒的,則掛起當前進程,直到設備就緒或者主動超時。被喚醒後它又要再次遍歷fd。
特點:
1:poll沒有最大連接數限制,因為它是用基於鏈表來存儲的,跟selelct直接監聽fd不一樣。
2:同樣的大量的fd的數組被整體復制與用戶態和內核地址空間之間。
3:poll還有一個特點是水平觸發:如果報告了fd後沒有被處理,則下次poll時還會再次報告該fd。
4:跟select一樣,在poll返回後,還是需要通過遍歷fdset來獲取已經就緒的socket。當fd很多時,效率會線性下降。

三:epoll

epoll支持水平觸發和邊緣觸發,最大的特點在於邊緣觸發,它只告訴進程哪些fd剛剛變為就緒態,並且只會通知一次。還有一個特點是,epoll使用「事件」的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內核就會採用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知。

沒有最大並發連接的限制,能打開的FD的上限遠大於1024(1G的內存上能監聽約10萬個埠)。

效率提升,不是輪詢的方式,不會隨著FD數目的增加效率下降。只有活躍可用的FD才會調用callback函數;即Epoll最大的優點就在於它只管你「活躍」的連接,而跟連接總數無關,因此在實際的網路環境中,Epoll的效率就會遠遠高於select和poll。

內存拷貝,利用mmap()文件映射內存加速與內核空間的消息傳遞;即epoll使用mmap減少復制開銷。

聊聊同步、非同步、阻塞與非阻塞
聊聊Linux 五種IO模型
聊聊IO多路復用之select、poll、epoll詳解

⑺ java網路io模型有幾種

#BIO---Blocking IO
- 每個socket一個線程,讀寫時線程處於阻塞狀態。
優點:實現簡單
缺點:無法滿足高並發,高接入的需求

- 不使用線程池的BIO模型,除了無法滿足高並發需求外,由於需要為每個請求創建一個線程,還可能因為接入大量不活躍連接而耗盡伺服器資源。

- 使用線程池的BIO模型,雖然控制了線程數量,但由於其本質上讀寫仍是阻塞的,仍無法滿足高並發需求。

#NIO---Non-Blocking IO(非阻塞IO)
##非阻塞IO和多路復用
非阻塞IO和多路復用實際上是兩個不用的概念,由於兩者通常結合在一起使用,因此兩者往往被混為一談。下面我將試著分清這兩個概念:
###非阻塞IO
與BIO相對應,非阻塞IO的讀寫方法無論是否有數據都立即返回,因此可以通過輪詢方式來實現,但輪詢方式的效率並不比BIO有顯著提高,因為每個連接仍然需要佔用一個線程。下面是輪詢方式實現的IO模式圖:

###多路復用
- 多路復用結合非阻塞IO能夠明顯提高IO的效率,這也是Java1.4把非阻塞IO和多路復用同時發布的原因。
- 多路復用的核心是多路復用器(Selector),它是需要操作系統底層支持的,簡單的說,就是進程把多個socket和它們關心的事件(比如連接請求或數據已准備好)都注冊在多路復用器上,操作系統會在事件發生時通知多路復用器,這樣進程就可以通過多路復用器知道在那個socket上發生了什麼時間,從而進行對應的處理。
- 多路復用的優點在於只需要一個線程監測(阻塞或輪詢方式均可)多路選擇器的狀態,只有在有事件需要發生時才會真正的創建線程進行處理,因此更適合高並發多接入的應用環境。

- 在Linux系統下,多路復用的底層實現是epoll方法,與select/poll的順序掃描不同,epoll採用效率更高的事件驅動方式,而且epoll方式並沒有socket個數限制。
##BIO和NIO的比較
- BIO適用於連接長期保持的應用,比如一個復雜系統中模塊之間通過長連接來進行通信。
- NIO加多路復用的模式更適合短連接、高並發、多接入的情形,比如網路伺服器。
##NIO網路編程的常用介面
##Reactor模式
Reactor模式用於解決事件分發處理的問題,Handler把自己的channel和關注的事件注冊到Selector中,當對應的事件發生在自己的channel上時,對應的handler就會得到通知並進行處理。
- 單線程的Reactor
消息的分發、讀寫、處理都在一個線程中處理,是Reactor最簡單的實現方式,如果消息的處理需要較長時間,會影響效率。

```java

//Reactor類,負責分發事件並調用對應的handler
class Reactor implements Runnable {

final Selector selector;

final ServerSocketChannel serverSocket;

//Reactor初始化

Reactor(int port) throws IOException {

selector = Selector.open();

serverSocket = ServerSocketChannel.open();

serverSocket.socket().bind(new InetSocketAddress(port));

serverSocket.configureBlocking(false); //必須配置為非阻塞

//Acceptor會在Reactor初始化時就注冊到Selector中,用於接受connect請求
SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT);

sk.attach(new Acceptor()); //attach callback object, Acceptor

}

//分發消息並調用對應的handler
public void run() {
try {

while (!Thread.interrupted()) {

selector.select();

Set selected = selector.selectedKeys();

Iterator it = selected.iterator();

while (it.hasNext())

dispatch((SelectionKey)(it.next()); //Reactor負責dispatch收到的事件

selected.clear();

}

} catch (IOException ex) { /* ... */ }

}

void dispatch(SelectionKey k) {

Runnable r = (Runnable)(k.attachment()); //調用之前注冊的callback對象

if (r != null)

r.run();

}

//Acceptor也是一個handler,負責創建socket並把新建的socket也注冊到selector中

class Acceptor implements Runnable { // inner

public void run() {

try {

SocketChannel c = serverSocket.accept();

if (c != null)

new Handler(selector, c);

}

catch(IOException ex) { /* ... */ }

}

}

}

//Concrete Handler:用於收發和處理消息。
//在當前的實現中,使用Runnable介面作為每個具體Handler的統一介面
//如果在處理時需要參數和返回值,也可以為Handler另外聲明一個統一介面來代替Runnable介面
final class Handler implements Runnable {

final SocketChannel socket;

final SelectionKey sk;

ByteBuffer input = ByteBuffer.allocate(MAXIN);

ByteBuffer output = ByteBuffer.allocate(MAXOUT);

static final int READING = 0, SENDING = 1;

int state = READING;

Handler(Selector sel, SocketChannel c) throws IOException {

socket = c; c.configureBlocking(false);

// Optionally try first read now

sk = socket.register(sel, 0);

sk.attach(this); //將Handler作為callback對象

sk.interestOps(SelectionKey.OP_READ); //第二步,接收Read事件

sel.wakeup();

}

boolean inputIsComplete() { /* ... */ }

boolean outputIsComplete() { /* ... */ }

void process() { /* ... */ }

public void run() {

try {

if (state == READING) read();

else if (state == SENDING) send();

} catch (IOException ex) { /* ... */ }

}

void read() throws IOException {

socket.read(input);

if (inputIsComplete()) {

process();

state = SENDING;

// Normally also do first write now

sk.interestOps(SelectionKey.OP_WRITE); //第三步,接收write事件

}

}

void send() throws IOException {

socket.write(output);

if (outputIsComplete()) sk.cancel(); //write完就結束了, 關閉select key

}

}

//上面 的實現用Handler來同時處理Read和Write事件, 所以裡面出現狀態判斷

//我們可以用State-Object pattern來更優雅的實現

class Handler { // ...

public void run() { // initial state is reader

socket.read(input);

if (inputIsComplete()) {

process();

sk.attach(new Sender()); //狀態遷移, Read後變成write, 用Sender作為新的callback對象

sk.interest(SelectionKey.OP_WRITE);

sk.selector().wakeup();

}

}

class Sender implements Runnable {

public void run(){ // ...

socket.write(output);

if (outputIsComplete()) sk.cancel();

}

}

}

```
- 多線程Reacotr
處理消息過程放在其他線程中執行

```java
class Handler implements Runnable {

// uses util.concurrent thread pool

static PooledExecutor pool = new PooledExecutor(...);

static final int PROCESSING = 3;

// ...

synchronized void read() { // ...

socket.read(input);

if (inputIsComplete()) {

state = PROCESSING;

pool.execute(new Processer()); //使用線程pool非同步執行

}

}

synchronized void processAndHandOff() {

process();

state = SENDING; // or rebind attachment

sk.interest(SelectionKey.OP_WRITE); //process完,開始等待write事件

}

class Processer implements Runnable {

public void run() { processAndHandOff(); }

}

}

```
- 使用多個selector
mainReactor只負責處理accept並創建socket,多個subReactor負責處理讀寫請求

```java
Selector[] selectors; //subReactors集合, 一個selector代表一個subReactor

int next = 0;

class Acceptor { // ...

public synchronized void run() { ...

Socket connection = serverSocket.accept(); //主selector負責accept

if (connection != null)

new Handler(selectors[next], connection); //選個subReactor去負責接收到的connection

if (++next == selectors.length) next = 0;

}

}

```
#AIO
AIO是真正的非同步IO,它於JDK1.7時引入,它和NIO的區別在於:
- NIO仍然需要一個線程阻塞在select方法上,AIO則不需要
- NIO得到數據准備好的消息以後,仍然需要自己把消息復制到用戶空間,AIO則是通過操作系統的支持把數據非同步復制到用戶空間以後再給應用進程發出信號。

⑻ 什麼是「同步IO」和「非同步IO」

同步IO在同一時刻只允許一個IO操作,也就是說對於同一個文件句柄的IO操作是序列化的,即使使用兩個線程也不能同時對同一個文件句柄同時發出讀寫操作。重疊IO允許一個或多個線程同時發出IO請求。

非同步IO的概念和同步IO相對。當一個非同步過程調用發出後,調用者不能立刻得到結果。實際處理這個調用的部件在完成後,通過狀態、通知和回調來通知調用者。在一個CPU密集型的應用中,有一些需要處理的數據可能放在磁碟上。預先知道這些數 據的位置,所以預先發起非同步IO讀請求。等到真正需要用到這些數據的時候,再等待非同步IO完成。使用了非同步IO,在發起IO請求到實際使用數據這段時間 內,程序還可以繼續做其他事情。

⑼ 什麼是 IO 模型

伺服器端編程經常需要構造高性能的IO模型,常見的IO模型有四種:
(1)同步阻塞IO(Blocking IO):即傳統的IO模型。

(2)同步非阻塞IO(Non-blocking IO):默認創建的socket都是阻塞的,非阻塞IO要求socket被設置為NONBLOCK。注意這里所說的NIO並非Java的NIO(New IO)庫。

(3)IO多路復用(IO Multiplexing):即經典的Reactor設計模式,有時也稱為非同步阻塞IO,Java中的Selector和Linux中的epoll都是這種模型。

(4)非同步IO(Asynchronous IO):即經典的Proactor設計模式,也稱為非同步非阻塞IO。

⑽ 請比較Linux與Windows在網路編程方面的特點

找了一段,大致涉及到了您的問題:

一、socket的模式
socket一般有兩種模式:同步和非同步(windows網路編程技術中也可叫鎖定和非鎖定,Linux網路編程叫阻塞和非阻塞)。

二、socket的類型

socket一般有三種類型,基於TCP的流式套接字,基於UDP的數據報套接字和原始套接字。

三、socket的IO模型

socket
的IO模型是編程中使用socket兩種模式的策略,它們適用的場合不同,在不同的操作系統上支持的模型也不同,例如windows從NT版本才開始支持
完成埠模型。Linux和Windows所支持的模型也有區別,當然也有相同的地方,可能叫法不一樣,但大致思路是一樣的,下面分別介紹windows
和Linux的IO模型

1、 Windows下的套接字IO模型:

A、 Select(選擇)模型
用於同步socket的狀態檢測模型,又叫(Linux)多路復用,可以同時檢測多個socket的狀態

B、 WSAAsyncSelect(非同步選擇)模型
用於非同步socket的非同步事件設置,它是基於Windows消息的模型,必須先打開一個窗口,然後把窗口和socket的消息綁定,這樣,在socket有消息通知時,操作系統便通知窗口,然後在窗口進行處理。

C、 WSAEventSelect(非同步事件)模型

於非同步socket的非同步事件,它是基於網路事件的模型,先使用CreateEvent創建一個事件,然後使用WSAEventSelect進行事件綁
定,然後可以使用WaitForMultipleObject(Event)進行事件監聽,可以同時監聽多個事件,不光是socket的,比如可以監聽使
用CreateWaitableTimer創建的Timer等。

D、 重疊IO模型

於非同步socket,在創建socket時需要在創建函數WSASocket中使用WSA_FLAG_OVERLAPPED標志,然後在投遞IO請求的時
候將一個Overlapped結構體指針賦給投遞函數,可以使用WSAWaitForMultipleObject來監聽事件,然後使用
WSAGetOverlappedResult來獲取IO的狀態,也可以在Overlapped結構體中使用完成常式來處理,即在投遞函數中把完成常式賦
給投遞函數。

E、 完成埠模型

是迄今為止最復雜的一種IO模型,當應用程序需要管理眾多的套接字並且希望隨著系統內安裝的CPU數目的增多,應用程序的性能也可以線性增加,就可以使用
這種模型,它的原理是每個CPU可以單獨負責一個線程的執行,避免線程的頻繁切換。使用這種模型往往可以達到最佳的系統性能。

先需要使用CreateIOCompletePort來創建完成埠,然後將IO句柄和此埠綁定,綁定也是使用此函數,當然也可以一次完成。接著是創建
工作者線程,工作者線程會使用GetQueuedCompletionStatus進入完成埠維護的線程池,當有完成事件時,會激活一個線程。

2、 Linux下的IO模型

A、阻塞IO

B、非阻塞IO

C、IO多路復用(選擇)

D、信號驅動
用於非同步socket,首先設定信號處理函數,然後使用fcntl函數設定socket的擁有者,像windows下使用WSAAsncSelect設定socket的窗口一樣。使用這種模型,當內核操作可以被操作的時候通知我們的應用程序

E、非同步IO
當內核在所有操作完成後才會通知應用程序

四、socket的一些使用上的優化

A、緩沖區的優化,可以考慮讓應用程序使用比較小的緩沖區,但同時使用多個WSARecv

B、使用socket選項SO_SNDBUF和SO_RCVBUF設置socket緩沖區大小,如果設為0,操作體系統會使用應用程序的緩沖區,這樣避免了從系統緩沖區向用戶區復制的開銷

五、注意這些IO模型有些不光是針對socket的,其他的IO操作也可以使用,最常用使用的是WriteFile,ReadFile等函數。

其它查考網址:
http://blog.163.com/tianle_han/blog/static/6617826200821522743948/
http://blog.csdn.net/yibulianhua/article/details/5374317

閱讀全文

與linuxio模型相關的資料

熱點內容
androidjava7 瀏覽:384
伺服器在山洞裡為什麼還有油 瀏覽:885
天天基金app在哪裡下載 瀏覽:972
伺服器軟路由怎麼做 瀏覽:289
冰箱壓縮機出口 瀏覽:225
OPT最佳頁面置換演算法 瀏覽:642
網盤忘記解壓碼怎麼辦 瀏覽:852
文件加密看不到裡面的內容 瀏覽:651
程序員腦子里都想什麼 瀏覽:430
oppp手機信任app在哪裡設置 瀏覽:185
java地址重定向 瀏覽:268
一年級下冊摘蘋果的演算法是怎樣的 瀏覽:448
程序員出軌電視劇 瀏覽:88
伺服器系統地址怎麼查 瀏覽:54
解壓游戲發行官 瀏覽:601
國外小伙解壓實驗 瀏覽:336
頂級大學開設加密貨幣 瀏覽:437
java重載與多態 瀏覽:528
騰訊應屆程序員 瀏覽:942
一鍵編譯程序 瀏覽:130