linux中fd_set的內部實現


一、在網絡編程中,經常用到selec系統調用來判斷套接字上是否存在數據可讀,或者能否向一個套接字寫入數據。其原型為:

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

其中,fd_set是一個socket集合,常用如下宏來對fd_set進行操作:

 

FD_CLR( s, *set)    //從set中刪除句柄s; 
FD_ISSET( s, *set)  //檢查句柄s是否存在與set中; 
FD_SET( s, *set )   //把句柄s添加到set中; 
FD_ZERO( *set )     //把set隊列初始為空.

 

需要說明一點,在內核中,socket對應struct socket結構,但在返回給用戶空間之前,內核做了一個關聯:調用get_unused_fd_flags從當前進程中獲取一個可用的文件描述符fd ,將struct socket結構關聯到該fd,並返回fd給用戶空間。所以在用戶空間中,socket為文件描述符。另外,進程可以打開的文件數是有限制的,為1024,故socket的取值小於1024。

 

二、fd_set是如何實現的呢?

試想由你實現這樣一個集合,可以往里添加任意0~1024之間的數(FD_SET操作),也可以將加入到集合中的數移除——移除一個(FD_CLR操作)或全部(FD_ZERO),你會如何實現?

一種比較好的思路是使用位圖bitmap,往集合了添加n時只需將第n個bit位置1,移除n時只需將第n個比特置為0,移除所有數據時,只需將所有bit置為0,可以通過memset操作來實現。fd_set的實現就是采用位圖bitmap(關於位圖可以參考《編程珠璣》第一章)。

 

其定義如下:

 

#define __NFDBITS (8 * sizeof(unsigned long))                //每個ulong型可以表示多少個bit, 
#define __FD_SETSIZE 1024                                          //socket最大取值為1024 
#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS)     //bitmap一共有1024個bit,共需要多少個ulong

typedef struct { 
    unsigned long fds_bits [__FDSET_LONGS];                 //用ulong數組來表示bitmap 
} __kernel_fd_set;

typedef __kernel_fd_set   fd_set;

 

  

對應的操作如下:

 

//每個ulong為32位,可以表示32個bit。
//fd  >> 5 即 fd / 32,找到對應的ulong下標i;fd & 31 即fd % 32,找到在ulong[i]內部的位置

#define __FD_SET(fd, fdsetp)   (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31)))             //設置對應的bit 
#define __FD_CLR(fd, fdsetp)   (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31)))            //清除對應的bit
#define __FD_ISSET(fd, fdsetp)   ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0)     //判斷對應的bit是否為1 
#define __FD_ZERO(fdsetp)   (memset (fdsetp, 0, sizeof (*(fd_set *)(fdsetp))))                             //memset bitmap

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM