linux socket編程---select

一、函數原型

 DESCRIPTION
       select() and  pselect()  allow  a  program  to  monitor  multiple  file
       descriptors,  waiting  until one or more of the file descriptors become
       "ready" for some class of I/O operation (e.g., input possible).  A file
       descriptor  is  considered  ready if it is possible to perform a corre‐
       sponding I/O operation (e.g., read(2) without  blocking,  or  a  suffi‐
       ciently small write(2)).
       
 int select(int nfds,					//需要檢查的號碼最高的文件描述符加 1 
 		    fd_set *readfds, 			//由 select()監視的讀文件描述符集合
 		    fd_set *writefds,			//由 select()監視的寫文件描述符集合 
            fd_set *exceptfds,			//由 select()監視的異常處理文件描述符集合 
            struct timeval *timeout);	//超時設定

  selecth和pselect允許程序監控一個或多個文件的狀態變化,以下分別介紹每個參數的意義。

二、struct fd_set

  在linux下任何設備、管道、FIFO等都是文件形式,這裏也包括socket。所以struct fd_set實際上就是一個文件描述符的集合。
  在實現上通過32bits實現對不同fd的狀態記錄。

/* We will use a 32-bit bitsets to represent the set of descriptors.  How
 * many uint32_t's do we need to span all descriptors?
 */
struct fd_set_s
{
  uint32_t arr[__SELECT_NUINT32];
};

  接下來要介紹幾個接口函數:

  • FD_ZERO(fd_set *);清空集合
  • FD_SET(int, fd_set *);將一個給定的文件描述符加入集合之中
  • FD_CLR(int, fd_set*);將一個給定的文件描述符從集合中刪除
  • FD_ISSET(int ,fd_set* );檢查集合中指定的文件描述符是否可以讀寫。

三、struct timeval

  struct timeval 是一個常用的結構,用來代表時間值,有兩個成員,一個是秒數,另一個是毫秒。

/* struct timeval represents time as seconds plus microseconds */
struct timeval
{
  time_t tv_sec;         /* Seconds */
  long tv_usec;          /* Microseconds */
};

四、舉個例子

EXAMPLE:
       #include <stdio.h>
       #include <stdlib.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int
       main(void)
       {
           fd_set rfds;
           struct timeval tv;
           int retval;

           /* Watch stdin (fd 0) to see when it has input. */
           FD_ZERO(&rfds);
           FD_SET(0, &rfds);

           /* Wait up to five seconds. */
           tv.tv_sec = 5;
           tv.tv_usec = 0;

           retval = select(1, &rfds, NULL, NULL, &tv);
           /* Don't rely on the value of tv now! */

           if (retval == -1)
               perror("select()");
           else if (retval)
               printf("Data is available now.\n");
               /* FD_ISSET(0, &rfds) will be true. */
           else
               printf("No data within five seconds.\n");

           exit(EXIT_SUCCESS);
       }

  這個例子是通過終端> man select拿到的,就以這個例子來做講解。

retval = select(1, &rfds, NULL, NULL, &tv);
  • int nfds:

  是一個整數值,是指集合中所有文件描述符的範圍,即所有文件描述符的最大值加1。

  • fd_set* readfds:

  是指向fd_set結構的指針,這個集合中應該包括可讀文件描述符,是否可以從這些文件中讀取數據了。
如果這個集合中有一個文件可讀,select就會返回一個大於0的值,表示有文件可讀;
如果沒有可讀的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0;
如果發生錯誤,則返回負值。
如果傳入的readfds的值是NULL值,則表示不關心任何文件的讀變化。

  • d_set* writefds:

  是指向fd_set結構的指針,這個集合中應該包括可寫文件描述符,是否可以向這些文件中寫入數據了。
如果這個集合中有一個文件可寫,select就會返回一個大於0的值,表示有文件可寫;
如果沒有可寫的文件,則根據timeout參數再判斷是否超時,若超出timeout的時間,select返回0;
如果發生錯誤,則返回負值。
如果傳入的writefds的值是NULL值,則表示不關心任何文件的讀變化。

  • fd_set * errorfds:

用來監視文件錯誤異常,和以上的兩個指針是相同用法,這裏不再贅述。

  • struct timeval* timeout:

  是設置select的超時時間
NULL,即不傳入時間結構,就是將select置於阻塞狀態,一定等到監視文件描述符集合中某個文件描述符發生變化爲止;
0秒0毫秒,(selcet變爲非阻塞函數),不管文件描述符是否有變化,都立刻返回繼續執行;
大於0,這就是等待的超時時間,即select在timeout時間內阻塞,超時時間之內有事件到來就返回了。

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