linux-socket編程(五)五種IO模型

1. 五種I/O模型

阻塞I/O

       

當套接口完成連接,可以使用recv函數向系統提出receive請求,來接收數據,這個請求是阻塞的,直到對等方發送數據過來。

非阻塞I/O

使用fcntl函數來將套接字改爲非阻塞模式。fcntl(fd, F_SETFL, flag|O_NONBLOCK);這時候recv函數即使沒有收到數據,也不會阻塞,會返回一個錯誤,返回值爲-1,錯誤代碼爲EWOULDBLOCK。如果還想獲取到數據,就再次提出請求。這個很少使用,由於它接受的過程相當於一個循環,對cpu資源的一種浪費,這種循環接收被稱之爲忙等待。

I/O複用(select和poll)

主要是通過select來實現的,select是用來管理多個文件描述符,當其中的一個或者多個檢測到有數據到來,select就返回,這時候在調用recv就不會阻塞了。實際上就是將阻塞的位置提前到了select上。核心思想就是使用select來管理多個文件描述符。

信號驅動I/O

當數據到來,它是以信號的方式來通知應用進程,應用進程要在信號處理程序中去處理接收數據的細節。

異步I/O

這個模型是效率最高的。使用aio_read來實現的。該函數提交一個請求,會遞交一個應用層緩存區,即使沒有數據到來,該函數也立刻返回,這時候應用進程就可以處理其它的事情達到異步處理的效果。當有數據到達時,就會將數據拷貝到該函數提供的緩存區中,複製完成後,會通過一個信號來通知應用進程的程序來處理數據。數據直接從內核推送到用戶的緩存區中。

2.select

int select(int nfds, fd_set *readfds, fd_set *writefds, 
fd_set *exceptfds, struct timeval *timeout);

參數分析:
fd_set *readfds 讀集合檢測到有數據可讀的套接口就會存放在這裏。
fd_set *writefds 可寫集合
fd_set *exceptfds 異常集合
struct timeval *timeout (超時結構體)超時時間,如果設置爲NULL表示必須等到有事件發生才返回,
如果設置了時間,就表示在這個時間範圍內如果沒有事件發生也會返回,返回事件個數爲0。
如果select返回失敗返回-1.
int nfds 存放在集合中的描述符的最大值+1,有關文件描述符的含義可以查看https://www.jianshu.com/p/a2df1d402b4d這篇文章。

select函數的作用相當於一個管理者,用來管理多個I/O一旦其中的一個I/O或者多個I/O檢測到我們感興趣的事件,select函數返回,返回值爲檢測到的事件個數。並且會返回那些I/O發生的事件。這樣就可以去遍歷這些事件,進而去處理這些事件。該函數的後四個參數都是輸入輸出參數,會根據實際情況,來修改內部的值。

使用到的函數:

void FD_CLR(int fd, fd_set *set);
作用是將fd這個文件描述符號,從這個set中移除。
int FD_ISSET(int fd, fd_set *set);
作用是判定fd該文件描述符,是否在這個集合當中
void FD_SET(int fd,fd_set *set);
作用是將fd添加到集合當中。
void FD_ZERO(fd_set *set);
作用是清空集合

 

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