阻塞式I/O编程有两个特点:

一、如果一个发现I\O有输入,读取的过程中,另外一个也有了输入,这时候不会产生任何反应.这就需要你的程序语句去用到select函数的时候才知道有数据输入。

二、程序去select的时候,如果没有数据输入,程序会一直等待,直到有数据位置,也就是程序中无需循环和sleep。

Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序

(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。

可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。

下面man下select函数的:

/* According to POSIX.1-2001 */

#include <sys/select.h>

/* According to earlier standards */

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,

fd_set *exceptfds, structtimeval *timeout);

第一,   struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(filedescriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Linux下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件,socket句柄就是一个文件描述符。

fd_set集合可以通过一些宏由人为来操作,

比如

清空集合FD_ZERO(fd_set*);

将一个给定的文件描述符加入集合之中FD_SET(int,fd_set *);

将一个给定的文件描述符从集合中删除FD_CLR(int,fd_set*);

检查集合中指定的文件描述符是否可以读写FD_ISSET(int,fd_set* )。
第二,structtimeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数,另一个是毫秒数。

具体解释select的参数:

int maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!

fd_set *readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。

fd_set *writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。

fd_set *errorfds同上面两个参数的意图,用来监视文件错误异常。

struct timeval* timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态,

第一,   若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;

第二,   第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;

第三,   timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,文件无变化返回0,有变化返回一个正值;

返回值:

负值:select错误

正值:某些文件可读写或出错

0:等待超时,没有可读写或错误的文件

举个简单的例子:

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include <sys/select.h>

#include<stdio.h>

#include<stdlib.h>

int main()

{

fd_setreadfds;

FD_ZERO(&readfds);

FD_SET(STDIN_FILENO,&readfds);

intret;

charbuf[256]={0};

structtimeval  tv={5,1000};

//       tv.tv_sec=5;

//       tv.tv_usec=1000;

ret=select(STDIN_FILENO+1,&readfds,NULL,NULL,&tv);

//ret=select(STDIN_FILENO+1,&readfds,NULL,NULL,NULL);

//ret=select(STDIN_FILENO+1,&readfds,NULL,NULL,0);

printf("ret=%d\n",ret);

if(ret==-1)

{

perror("selsecterror ");

exit(EXIT_FAILURE);

}

elseif(ret)

{

if(FD_ISSET(STDIN_FILENO,&readfds))

read(STDIN_FILENO,buf,256);

printf("readfrom stdin msg : %s\n",buf);

}

else

printf("timeout\n");

return0;

}

运行结果:3中状态:

1.    错误。

2.    超时,在指定的时间内没有检测到用户的输入。Selsect()返回0如图:

3.用户输入了,即检测到了标准输入已经准备好了

下面我们看一下socket编程中select()函数的使用。

在此之贴出select函数部分。

客户端:

while(1)
    {
         FD_ZERO(&readfds);
        FD_SET(sockfd,&readfds);
        FD_SET(STDIN_FILENO,&readfds);
        maxfd=sockfd;
        printf("before select %d\n",readfds);
      if((ret=select(maxfd+1,&readfds,NULL,NULL,NULL))==-1)
      { 
          perror("select:");
          exit(EXIT_FAILURE);
      }
      //哪个文件描述符准备好了就将那个所对应的位设置为1,其他的设置为0
      //eg:socket=3准备好了则readfds为00000100(8)
      //select 函数的返回值为:准备好的文件描述符的个数。
         DEBUG("ret=%d\n",ret);
        printf("after select %d\n",readfds);
  
     if(FD_ISSET(sockfd,&readfds))
        { printf("sockfd select %d\n",readfds);
           if(read(sockfd,read_buf,sizeof(read_buf))<=0)
           {
             perror("read <=0 ");
             break;
           }
          printf("%s\n",read_buf);
          memset(read_buf,0,sizeof(read_buf));
        }    
        if(FD_ISSET(STDIN_FILENO,&readfds)) //有标准输入描述符准备好了
        {  printf("STDIN_FILENO select %d\n",readfds);
         
           read(STDIN_FILENO,buf,sizeof(buf));   
          //或 scanf("%s",buf);//从标准输入设备的缓冲区中取出内容放到buf中
          write(sockfd, buf, strlen(buf)+1);
        }
         
    }

服务端:

void server_write_read(int sockfd)
{

fd_set  rfds;
    FD_ZERO(&rfds); 
    FD_SET(sockfd,&rfds);
    int i, maxfd = sockfd,ret=-1;
    int newfd;
    struct sockaddr_in client;
   socklen_t len = sizeof(client);
   char buf[MAXBUF] = {'\0'};
    while(1)
    {
             FD_ZERO(&rfds);  //clear set
             for(i = 0; i < MAXCLIENT; i++)
           {
              // add fd to set
              if(connfd[i].fd != 0)
              {
                FD_SET(connfd[i].fd ,&rfds);
              }
              //get tje max fd
              if(connfd[i].fd != 0  &&connfd[i].fd> maxfd)
              {
                maxfd=connfd[i].fd;
               
              }
            }
         FD_SET(sockfd,&rfds);
         printf("server_write_read  before select %d\n",rfds);
         if((ret=select(maxfd+1,&rfds,NULL,NULL,NULL))==-1)
       { 
           perror("select:");
           continue;
       }
       printf("server_write_read  after select %d\n",rfds);
       if(FD_ISSET(sockfd, &rfds))
       {       printf("server_write_read  sockfd %d\n",rfds);
           newfd = accept(sockfd, (struct sockaddr *)&client, &len);
           if(-1 == newfd)
            system_error("accept");
            else
             printf("welcome  %s was connected.\n", inet_ntoa(client.sin_addr));
          DEBUG("newfd=%d\n",newfd);
           //save socket description
           for(i = 0; i < MAXCLIENT; i++)
           {
              if(connfd[i].fd == 0)
              {
                 connfd[i].fd = newfd;
                 break;
              }
            }
        
     }
  
   for(i = 0; i < MAXCLIENT; i++)
   { 
      if(FD_ISSET(connfd[i].fd, &rfds))
      {
            if(connfd[i].fd == 0)continue;
         if ((read(connfd[i].fd, buf, MAXBUF)) <= 0)
           {DEBUG("server read <=0\n");
             for(i = 0; i < MAXCLIENT; i++)
             {
               if(connfd[i].fd==newfd)
                {
                  connfd[i].fd=0;
                  break;
                }
             }
             close(newfd);
             FD_CLR(newfd, &rfds);
           }
           else
           {
               int j=0;
               printf("// buf=%s\n",buf);
              for(; chat_func[j].func; j++)
              {
                if (buf[0] == chat_func[j].protocol)
                {
                 chat_func[j].func(buf, connfd[i].fd);
                 break;
                }
             }
             memset(buf,0,MAXBUF); 
           } 
      }
    
    }
       
   }
  
}

Linux中select函数的使用 select() Linux linux函数 select相关推荐

  1. Linux 中 dlopen、dlsym、dlclose、dlerror函数

    编译时候要加入 -ldl (指定dl库) dlopen 基本定义 功能:打开一个动态链接库  [喝小酒的网摘]http://blog.const.net.cn/a/17154.htm 包含头文件:  ...

  2. linux中oracle静默安装失败,oracle 11 Linux 静默安装 步骤及错误解决(更新中)

    oracle 11 Linux 静默安装 步骤及错误解决(更新中) oracle 11 Linux 静默安装 步骤及错误解决(更新中) [待更新] oracle成功安装完成后 显示的页面如下 : 此时 ...

  3. linux中lockf的例子,小何讲Linux: 文件锁及其实例

    1.  文件锁基本概念 Linux中软件.硬件资源都是文件(一切皆文件),文件在多用户环境中是可共享的. 文件锁是用于解决资源的共享使用的一种机制:当多个用户需要共享一个文件时,Linux通常采用的方 ...

  4. linux中c语言结构体详解,Linux C语言结构体-学习笔记

    Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...

  5. linux中文件记录的时间参数,【Linux】stat命令查看文件的三个时间参数

     在Windows中创建一个文件都会有相应的创建时间,修改时间,访问时间来记录文件的一些属性.在Linux中也不例外,文件也有三个时间来记录文件的变动,这三个时间分别是Modification t ...

  6. ubuntu 安装yum_如何在 Linux 中安装微软的 .NET Core SDK | Linux 中国

    本分步操作指南文章解释了如何在 Linux 中安装 .NET Core SDK 以及如何使用 .NET 开发出第一个应用程序.-- Sk致谢译自 | ostechnix.com 作者 | Sk译者 | ...

  7. 查看linux中的sh指向哪,什么是Linux的Shell脚本和怎么执行脚本?

    1.什么是Shell?shell shell是外壳的意思,就是操做系统的外壳.咱们能够经过shell命令来操做和控制操做系统,好比Linux中的Shell命令就包括ls.cd.pwd等等.总结来讲,S ...

  8. linux中cd命令及范例,15个Linux中的“cd”命令的实际示例

    在Linux中"CD"( 更改目录 )命令是新手以及系统管理员中最重要和最广泛使用的命令之一. 对于无头的服务器上管理员,"CD"是导航到一个目录来查看日志,执 ...

  9. linux中如何运行html文件路径问题,Linux中如何查询运行文件的全路径的方法

    在linux中,有些地方需要使用绝对路径,对于一些命令,如java.mysql等,需要使用到运行文件所在的路径,给大家介绍一个命令,来查询这个路径. which 可以通过which查询运行文件的所在路 ...

  10. linux中c语言生日快乐_生日快乐,Linux:27岁

    linux中c语言生日快乐 Linux今天庆祝了另一个生日-27岁! 与我们分享激动之情,我们无比高兴. 我们的许多读者都是Linux用户,粉丝,书呆子...形容他们的形容词清单不胜枚举. 你会怎么称 ...

最新文章

  1. leetcode_1. Two Sum
  2. 我国拟开展2016年新型智慧城市评价工作
  3. 克隆Centos 无法上网
  4. 排序和顺序统计学(2)——快速排序
  5. Scala模式匹配(类似Java的switch)
  6. webmin升级php,Webmin php-lib.pl修改
  7. 201521123057 《Java程序设计》第12周学习总结
  8. TensorFlow 第四步 多层神经网络 Mnist手写数字识别
  9. memcache 防火墙策略
  10. 用Spire.doc来合并邮件
  11. 51Nod-2148 字符出现位置【水题】
  12. Latex中参考文献排序
  13. 对研发经理这一岗位的个人理解
  14. html5使用mescroll
  15. qqxml图片代码_QQxml卡片代码合集超大图、清明上河图、官方认证推荐等
  16. 【190302】VC+ 视频捕捉与录像+实例源码源代码
  17. 2017双11核心技术揭秘—双十一海量数据下EagleEye的使命和挑战
  18. 精通CSS(5.6.3-end)PixyFairypureCSSToolHintscale
  19. HWND与HANDLE的区别
  20. Tuscany SCA V1.0中的扩展机制和启动过程中的扩展点[11月29日更新]

热门文章

  1. Nordic Collegiate Programming Contest 2016
  2. 微服务Spring Cloud Eureka 服务端-基本配置(eureka.server.xxx)
  3. rem + vw 布局
  4. 不要让Javascript的等价表格看上去那么难看
  5. “叔叔,你来监考了!”
  6. linux CP命令覆盖不提示方法
  7. NASA 美国国家航空航天局开源项目列表
  8. python解析css文件_Python格式化css文件的方法
  9. 微信小程序单指拖拽和双指缩放旋转
  10. vue 子组件给父组件传值