如上圖,咱們寫的應用程序使用數據流(UDP)Socket接收數據,調用recvfrom()
系統函數接收網卡上的數據。在阻塞I/O下,調用recvfrom()
將形成進程阻塞,直到數據接收完畢。異步
內存空間有系統空間和用戶空間,而且都有相應的緩衝區:async
如上圖,一樣應用程序調用數據流(UDP)Socket接收數據,調用recvfrom()
系統函數,而且設置了Socket爲non-blocking非阻塞。函數
這時咱們調用系統函數recvfrom()
則不阻塞進程,若是數據沒有在系統空間的緩衝區內準備好,則當即返回一個error,直接獲得一個結果,這時候進程能夠作點其餘任務而不用阻塞在這裏。可是若是數據在系統空間內的緩衝區準備好了,則將開始從系統空間拷貝數據到用戶空間。操作系統
I/O多路複用大體狀況如上圖。I/O多路複用也就是咱們常說的select、poll以及epoll,它可以使一個進程可以同時處理更多的鏈接。指針
這裏就以select爲例:select()
也是一個系統調用,若是一個進程調用了select()
那麼這個進程也會被阻塞。code
select()
,這時該進程阻塞,不過內核會監視應用程序向select註冊的全部Socket。若是註冊的Socket中有數據以及在系統空間緩衝區裏準備好了的,則該進程被喚醒。select()
的阻塞中返回,應用程序進程只能知道向select註冊的Socket裏有數據準備好的Socket,可是並不知道具體是哪一個Socket數據準備好了。因此,應用程序須要本身遍歷Socket,找出數據準備好的Socket,而後調用recvfrom()
函數將系統空間緩衝區內數據複製到用戶空間緩衝區內。Linux內核定義了不少信號,如SIGUSR1和SIGUSR2都是能夠用戶自定義發送/處理的信號。cdn
應用程序首先須要安裝信號處理器(即提供一個回調函數給內核),當相應事件發生的時候,操做系統會激活該信號,處理權交給進程,由進程調用處理該信號的回調函數。blog
在信號驅動I/O中,應用程序先安裝信號處理器,返回結果,進程能夠繼續執行。當數據在系統空間內準備好了後,內核會激活信號,進程則會調用相應的回調函數(這裏數據準備好了則直接調用recvfrom()
函數),而後數據則直接拷貝到用戶空間緩衝區內。進程
異步I/O則是調用aio_read()
系統函數,傳入了用戶空間緩衝區的地址指針。調用後進程不會被阻塞,則能夠作其餘事情,內核會在將數據複製到系統空間緩衝區,而後再將數據複製到用戶提供的用戶緩衝區地址中。都作完了後,則內核發送一個signal通知應用程序read完成了。這時應用程序以前提供的回調函數,由該進程來執行。事件