目錄
1.多路轉接技術的產生背景
2.select
3.poll
3.epoll
1.多路轉接技術的產生背景
一個技術的出現必然有它要解決的問題,那么多路轉接解決的問題是什么嗯?
我們知道,一個進程里面有一個文件描述符表管理這個進程所打開的文件,我們進行網絡通信的時候,本質就是創建一個網絡文件進行通信,我們可能會同時多個文件進行通信。
文件進行通信,不就是進行IO嗎?就要進行讀取,就要進行寫入,但是在網絡中,我們數據的發送需要時間,我們一個一個等就是串行的,效率低下,為了解決這種問題,我們提出多路轉接,就是OS提供系統調用,底層去同時等待多個fd,而非去等待一個fd,假如我們一秒一個文件準備就緒的概率是百分之一,如果我同時等待100個文件,理論上幾乎每秒都會有文件就緒,所以大大降低了我們等待的時間,我們IO抽象出來就是等待+拷貝,讀是一種拷貝,寫也是一種拷貝,通常,我們等待的時間是大于拷貝的時間,我們通過多路轉接的形式,不就可以降低等待的時間,單位時間內更多的數據被拷貝,效率提高。
我們在代碼中的scanf不就是一種等待嗎?如果我的數據不輸入,它就一直在那里阻塞,當鍵盤數據準備就緒,觸發硬件中斷,通知操作系統去處理鍵盤的數據,這樣效率低下,我們等的時間太長了,所以我們要對我們讀取的文件進行非阻塞的設計。
鍵盤不就緒抽象出來就是讀的條件不就緒,我把文件設計成非阻塞模式,那么它就不會阻塞住。
fcntl的第一行是獲取選項,然后第二個是對fd的模式進行設計,采用|可以對模式進行添加。
如果我們的文件read條件不就緒就會出錯,這里就會引發兩種情況,一種是我的read真的出錯了,一種是我的read數據沒有準備好,沒有真的出錯,我們需要對這種情況進行處理。
在我們的read錯誤會返回對應的錯誤碼,我們可以用errno對錯誤碼進行提取,判斷,如果是讀的條件未就緒,我們就放行,讓它進行下一次檢查,如果寫端關閉read返回0,如果錯誤,返回小于0 的數,直接break;
errno是一個全局變量。
EINTR表示當我們正在讀取的時候,它進行了線程切換,導致我們讀到一半失敗了,再回來的時候可能就不再讀取了,我們還需要再次進行讀取。
#include<iostream>
#include<unistd.h>
#include<fcntl.h>
void setnoblock(int fd)
{int fl=fcntl(fd,F_GETFL);fcntl(fd,F_SETFL,fl | O_NONBLOCK);
}
int main()
{ setnoblock(0);//設置為非阻塞char buffer[64];while(true){int n=read(0,buffer,sizeof(buffer)-1);if(n>0){// buffer[n]=0;printf("#%s",buffer);}else if(n==0){perror("read");break;}else {if(errno==EAGAIN){printf("你的數據沒有準備好,下次再來\n");//在這里下面的邏輯就可以做其他事情了。sleep(1);continue;}else if(errno==EINTR){continue;}else{perror("read");break;}}}return 0;
}
2.select
知道了多路轉接的來源之后,我們了解多路轉接就是為了提高IO效率而誕生的,所以我們來介紹一下具體的系統為我們提供的接口select。IO=等+拷貝,select為了降低等的時間而誕生。
是一種具體的方案,而不是一種抽象的所謂的降低等的效率的抽象概念。這里認為任何抽象的概念都應該建立在具體的實現上面,沒有實踐理解, 怎么理解這么抽象的概念?
、、 它的功能是監視有沒有文件描述符發生變化。
sel