1. 程式人生 > >非同步套接字基礎:多路複用、select函式以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

非同步套接字基礎:多路複用、select函式以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

select函式: 
      系統提供select函式來實現多路複用輸入/輸出模型。原型: 
       #include sys/time.h> 
       #include unistd.h> 
       int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout); 
      引數maxfd是需要監視的最大的檔案描述符值+1;rdset,wrset,exset分別對應於需要檢測的可讀檔案描述符的集合,可寫檔案描述符的集 合及異常檔案描述符的集合。struct timeval結構用於描述一段時間長度,如果在這個時間內,需要監視的描述符沒有事件發生則函式返回,返回值為0。 

       FD_ZERO,FD_SET,FD_CLR,FD_ISSET: 引數maxfd是需要監視的最大的檔案描述符值+1;rdset,wrset,exset分別對應於需要檢測的可讀檔案描述符的集合,可寫檔案描述符的集 合及異常檔案描述符的集合。struct timeval結構用於描述一段時間長度,如果在這個時間內,需要監視的描述符沒有事件發生則函式返回,返回值為0。 
FD_ZERO,FD_SET,FD_CLR,FD_ISSET: 
       FD_ZERO(fd_set *fdset);將指定的檔案描述符集清空,在對檔案描述符集合進行設定前,必須對其進行初始化,如果不清空,由於在系統分配記憶體空間後,通常並不作清空處理,所以結果是不可知的。 

       FD_SET(fd_set *fdset);用於在檔案描述符集合中增加一個新的檔案描述符。 
       FD_CLR(fd_set *fdset);用於在檔案描述符集合中刪除一個檔案描述符。 
       FD_ISSET(int fd,fd_set *fdset);用於測試指定的檔案描述符是否在該集合中。 

struct timeval結構: 

       struct timeval
       { 

       long tv_sec;//second 
       long tv_usec;//minisecond 
      } 
timeout設定情況: 
       null
:select將一直被阻塞,直到某個檔案描述符上發生了事件。 
       0:僅檢測描述符集合的狀態,然後立即返回,並不等待外部事件的發生。 
       特定的時間值:如果在指定的時間段裡沒有事件發生,select將超時返回。 


fd_set

它是一組檔案描述符(fd)的集合。由於fd_set型別的長度在不同平臺上不同,因此應該用一組標準的巨集定義來處理此類變數:

fd_set set;
FD_ZERO(&set);         /* 將set清零 */
FD_SET(fd, &set);       /* 將fd加入set */
FD_CLR(fd, &set);       /* 將fd從set中清除 */
FD_ISSET(fd, &set);    /* 如果fd在set中則真*/ 

在過去,一個fd_set通常只能包含少於等於32個檔案描述符,因為fd_set其實只用了一個int的位元向量來實現,在大多數情況下,檢查 fd_set能包括任意值的檔案描述符是系統的責任,但確定你的fd_set到底能放多少有時你應該檢查/修改巨集FD_SETSIZE的值。*這個值是系 統相關的*,同時檢查你的系統中的select() 的man手冊。有一些系統對多於1024個檔案描述符的支援有問題。


多路複用

多路複用的方式是真正實用的伺服器程式,非多路複用的網路程式只能作為學習或著陪測的角色。本文說下個人接觸過的多路複用函式:select/poll/epoll/port。kqueue的*nix系統沒接觸過,估計熟悉了上面四種,kqueue也只是需要熟悉一下而已。

一、select模型
select原型: int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
其中引數n表示監控的所有fd中最大值+1。
和select模型緊密結合的四個巨集,含義不解釋了:
FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);
理解select模型的關鍵在於理解fd_set,為說明方便,取fd_set長度為1位元組,fd_set中的每一bit可以對應一個檔案描述符fd。則1位元組長的fd_set最大可以對應8個fd。
(1)執行fd_set set; FD_ZERO(&set);則set用位表示是0000,0000。
(2)若fd=5,執行FD_SET(fd,&set);後set變為0001,0000(第5位置為1)
(3)若再加入fd=2,fd=1,則set變為0001,0011
(4)執行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都發生可讀事件,則select返回,此時set變為0000,0011。注意:沒有事件發生的fd=5被清空。
基於上面的討論,可以輕鬆得出select模型的特點:
(1)可監控的檔案描述符個數取決與sizeof(fd_set)的值。我這邊服務 器上sizeof(fd_set)=512,每bit表示一個檔案描述符,則我伺服器上支援的最大檔案描述符是512*8=4096。據說可調,另有說雖 然可調,但調整上限受於編譯核心時的變數值。本人對調整fd_set的大小不太感興趣,參考http://www.cppblog.com /CppExplore/archive/2008/03/21/45061.html中的模型2(1)可以有效突破select可監控的檔案描述符上 限。
(2)將fd加入select監控集的同時,還要再使用一個數據結構array儲存放到select監控集中的fd,一是用於再select 返回後,array作為源資料和fd_set進行FD_ISSET判斷。二是select返回後會把以前加入的但並無事件發生的fd清空,則每次開始 select前都要重新從array取得fd逐一加入(FD_ZERO最先),掃描array的同時取得fd最大值maxfd,用於select的第一個 引數。
(3)可見select模型必須在select前迴圈array(加fd,取maxfd),select返回後迴圈array(FD_ISSET判斷是否有時間發生)。

下面給一個偽碼說明基本select模型的伺服器模型:
array[slect_len];
nSock=0;
array[nSock++]=listen_fd;(之前listen port已繫結並listen)
maxfd=listen_fd;
while{
FD_ZERO(&set);
foreach (fd in array) 
{
   fd大於maxfd,則maxfd=fd
   FD_SET(fd,&set)
}
res=select(maxfd+1,&set,0,0,0);
if(FD_ISSET(listen_fd,&set))
{
   newfd=accept(listen_fd);
   array[nsock++]=newfd;
   if(--res=0) continue
}
foreach 下標1開始 (fd in array) 
{
      if(FD_ISSET(fd,&set))
          執行讀等相關操作
          如果錯誤或者關閉,則要刪除該fd,將array中相應位置和最後一個元素互換就好,nsock減一
      if(--res=0) continue
}
}


相關推薦

非同步基礎select函式以及FD_ZEROFD_SETFD_CLRFD_ISSET

select函式:       系統提供select函式來實現多路複用輸入/輸出模型。原型:        #include sys/time.h>        #include unistd.h>        int select(int maxfd,f

非同步基礎select函式以及FD_ZEROFD_SETFD_CLRFD_ISSET

select函式:           系統提供select函式來實現多路複用輸入/輸出模型。原型:         #include sys/time.h>         #include unistd.h>       select函式:    

11 非阻塞與IO(進階)

img 一行 回調 lba let 自己 elf accept error: 1、非阻塞套接字 第一部分 基本IO模型 1.普通套接字實現的服務端的缺陷 一次只能服務一個客戶端! 2.普通套接字實現的服務端的瓶頸!!! accept阻塞! 在沒有新的套接字來之前,不能處

HTTP協議篇(一)資料流

管道機制、多路複用 管道機制(Pipelining)  HTTP 1.1 引入了管道機制(Pipelining),即客戶端可通過同一個TCP連線同時傳送多個請求。如果客戶端需要請求兩個資源,以前的做法是在同一個TCP連線裡面,先發送A請求,然後等待伺服器做出迴應,收到後再

網路通訊 IOselectpollepoll詳解

 目前支援I/O多路複用的系統呼叫有 select,pselect,poll,epoll,I/O多路複用就是通過一種機制,一個程序可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,pselect,poll,epoll

Linux網路程式設計---I/Oselect

1.I/O多路複用(IO multiplexing) 我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。

Linux IOselect

Linux IO多路複用之select 首先,我我們來介紹一下什麼是IO多路複用: IO多路複用是指核心一旦發現程序指定的一個或者多個IO條件準備讀取,它就通知該程序。 IO多路複用適用如下場合: 當客戶處理多個描述符時(一般是互動式輸入和網路套介面),

IO select(高效併發伺服器)

一、I/O 多路複用概述   I/O 多路複用技術是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。   select,poll,epoll都是I/O多路複用的機制。I/O多路複用通過一種機制,可以監視多個描述符,一旦某個

嵌入式Linux網路程式設計,I/Oselect()示例,select()客戶端,select()伺服器,單鏈表

文章目錄 1,IO複用select()示例 1.1 select()---net.h 1.2 select()---client.c 1.3 select()---sever.c 1.4 select()---linklist.h

I/Oselectpollepoll

很早之前有寫過篇IO多路複用的文章:https://www.cnblogs.com/klcf0220/archive/2013/05/14/3077003.html 參考連結:https://segmentfault.com/a/1190000003063859 select,poll,epoll都是IO多路

Linuxselect/poll/epoll實現原理及優缺點對比

一、select的實現原理 支援阻塞操作的裝置驅動通常會實現一組自身的等待佇列如讀/寫等待佇列用於支援上層(使用者層)所需的BLOCK或NONBLOCK操作。當應用程式通過裝置驅動訪問該裝置時(預設為

IOselectpollepoll詳解

  ET(edge-triggered)是高速工作方式,只支援no-block socket。在這種模式下,當描述符從未就緒變為就緒時,核心通過epoll告訴你。然後它會假設你知道檔案描述符已經就緒,並且不會再為那個檔案描述符傳送更多的就緒通知,直到你做了某些操作導致那個檔案描述符不再為就緒狀態了(比如,你在

淺談網路I/O模型 select & poll & epoll

我們首先需要知道select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,

IOselect總結

轉載自 阻塞式I/O程式設計有兩個特點:  一、如果一個發現I\O有輸入,讀取的過程中,另外一個也有了輸入,這時候不會產生任何反應,也就是需要你的程式語句去select的時候才知道有資料輸入。  二、程式去select的時候,如果沒有資料輸入,程式會一直等待,直到有資

Linux下詳解---epoll模式下的IO伺服器

1 epoll模型簡介 epoll可是當前在Linux下開發大規模併發網路程式的熱門人選,epoll 在Linux2.6核心中正式引入,和select相似,其實都I/O多路複用技術而已,並沒有什麼神祕的。 其實在Linux下設計併發網路程式,向來不缺少方法,比如典型的Apache模型(Proce

Visual C++網路程式設計經典案例詳解 第3章 執行緒與非同步程式設計 實現執行緒同步 互斥物件 使用API函式操作互斥物件

互斥物件和臨界區物件和事件物件作用一樣 用於實現執行緒同步 互斥物件可以線上程中使用 CreateMutex()建立並返回互斥物件 原型如下 HANDLE CreateMutex(   LPSECURITY_ATTIRIBUTES lpMutexAttributes,  

Visual C++網路程式設計經典案例詳解 第3章 執行緒與非同步程式設計 實現執行緒同步 互斥物件 程式的唯一執行

互斥物件可在程序中使用 使用者在程序建立互斥物件實現程式例項唯一執行 建立控制檯工程 #include<windows.h>                                //包含標頭檔案 #include<stdio.h> in

Visual C++網路程式設計經典案例詳解 第3章 執行緒與非同步程式設計 程序間通訊 命名管道 命名管道例項

vc新增控制檯工程 名字命名管道例項 新增原始檔 名字 伺服器 #include<windows.h>                                //包含標頭檔案 #include<stdio.h> int main() {  

分解;UDP報文段格式;和埠號

UDP套接字(目的IP地址,目的埠號),若兩個UDP報文段有不同源IP地址和/或源埠號,但有相同目的IP地址和目的埠號,則這兩個報文段將通過相同的套接字被定向到相同的目的程序。TCP套接字(源IP地址,源埠號,目的IP地址,目的埠號),當一個TCP報文段從網路到達一臺主機時,

Linux下詳解(十)---epoll模式下的IO伺服器

1 epoll模型簡介 epoll可是當前在Linux下開發大規模併發網路程式的熱門人選,epoll 在Linux2.6核心中正式引入,和select相似,其實都I/O多路複用技術而已,並沒有什麼神祕的。 其實在Linux下設計併發網路程式,向來不缺少