1. 程式人生 > >linux之select函式解析

linux之select函式解析

select()的機制中提供一fd_set的資料結構,實際上是一long型別的陣列, 每一個數組元素都能與一開啟的檔案控制代碼(不管是Socket控制代碼,還是其他 檔案或命名管道或裝置控制代碼)建立聯絡,建立聯絡的工作由程式設計師完成, 當呼叫select()時,由核心根據IO狀態修改fd_set的內容,由此來通知執 行了select()的程序哪一Socket或檔案可讀,下面具體解釋:#include int select(nfds, readfds, writefds, exceptfds, timeout)
 
  int nfds;fd_set *readfds, *writefds, *exceptfds;struct timeval *timeout;ndfs:select監視的檔案控制代碼數,視程序中開啟的檔案數而定,一般設為呢要監視各檔案 中的最大檔案號加一。
 
  readfds:select監視的可讀檔案控制代碼集合。
 
  writefds: select監視的可寫檔案控制代碼集合。
 
  exceptfds:select監視的異常檔案控制代碼集合。
 
  timeout:本次select()的超時結束時間。(見/usr/sys/select.h, 可精確至百萬分之一秒!)
 
  當readfds或writefds中映象的檔案可讀或可寫或超時,本次select() 就結束返回。程式設計師利用一組系統提供的巨集在select()結束時便可判 斷哪一檔案可讀或可寫。對Socket程式設計特別有用的就是readfds. 幾隻相關的巨集解釋如下:FD_ZERO(fd_set *fdset):清空fdset與所有檔案控制代碼的聯絡。
 
  FD_SET(int fd, fd_set *fdset):建立檔案控制代碼fd與fdset的聯絡。
 
  FD_CLR(int fd, fd_set *fdset):清除檔案控制代碼fd與fdset的聯絡。
 
  FD_ISSET(int fd, fdset *fdset):檢查fdset聯絡的檔案控制代碼fd是否可讀寫,>0表示可讀寫。
 
  (關於fd_set及相關巨集的定義見/usr/include/sys/types.h)
 
  這樣,你的socket只需在有東東讀的時候才讀入,大致如下:……
 
  int sockfd;fd_set fdR;struct timeval timeout = ……;……
 
  for(;;) { FD_ZERO(&fdR);FD_SET(sockfd, &fdR);switch (select(sockfd + 1, &fdR, NULL, &timeout)) { case -1:error handled by u;case 0:timeout hanled by u;default:if (FD_ISSET(sockfd)) { now u read or recv something;/* if sockfd is father and server socket, u can now accept() */ }所以一個FD_ISSET(sockfd)就相當通知了sockfd可讀。
 
  至於struct timeval在此的功能,請man select.不同的timeval設定 使使select()表現出超時結束、無超時阻塞和輪詢三種特性。由於timeval可精確至百萬分之一秒,所以Windows的SetTimer()根本不算 什麼。你可以用select()做一個超級時鐘。

[[email protected] select]$ cat select.c 

/*********************************************************************************
 *      Copyright:  (C) 2013 fulinux<[email protected]
 *                  All rights reserved.
 *
 *       Filename:  select.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(07/31/2013~)
 *         Author:  fulinux <
[email protected]
>
 *      ChangeLog:  1, Release initial version on "07/31/2013 02:18:45 PM"
 *                 
 ********************************************************************************/


#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>


int main(void)
{
    int fds[2];
    char buf[7];
    int i,rc,maxfd;
    fd_set inset1,inset2;
    struct timeval tv;


    if((fds[0] = open("hello1",O_RDWR|O_CREAT,0666)) < 0)
        perror("open hello1");
    if((fds[1] = open("hello2",O_RDWR|O_CREAT,0666)) < 0)
        perror("open hello2");
    if((rc = write(fds[0],"Hello!\n",7)))
        printf("rc = %d\n",rc);
    lseek(fds[0],0,SEEK_SET);


    maxfd = fds[0] > fds[1] ? fds[0] : fds[1];


    FD_ZERO(&inset1);
    FD_SET(fds[0],&inset1);
    FD_ZERO(&inset2);
    FD_SET(fds[1],&inset2);
    tv.tv_sec = 2;
    tv.tv_usec = 0;


    while(FD_ISSET(fds[0],&inset1)||FD_ISSET(fds[1],&inset2))
    {
        if(select(maxfd+1,&inset1,&inset2,NULL,&tv) < 0)
            perror("select");
        else
        {
            if(FD_ISSET(fds[0],&inset1))
            {
                rc = read(fds[0],buf,7);
                if(rc > 0)
                {
                    buf[rc] = '\0';
                    printf("read: %s\n", buf);
                }
                else
                    perror("read");
            }
        }
            
        if(FD_ISSET(fds[1],&inset2))
        {
            rc = write(fds[1],buf,7);
            if(rc > 0)
            {
                buf[rc] = '\0';
                printf("rc = %d, write: %s\n", rc,buf);
            }
            else
                perror("write");
            sleep(3);
        }
    }
    exit(0);
}

[

[email protected] select]$ 

[[email protected] select]$ ls
select.c
[[email protected] select]$ gcc select.c 
[[email protected] select]$ ./a.out 
rc = 7
read: Hello!


rc = 7, write: Hello!


read: Success
rc = 7, write: Hello!


read: Success
rc = 7, write: Hello!


read: Success
rc = 7, write: Hello!


read: Success
rc = 7, write: Hello!


^C
[[email protected] select]$ cat hello1
Hello!
[[email protected] select]$ cat hello2
Hello!
Hello!
Hello!
Hello!
Hello!
[[email protected] select]$