select函数

该函数允许进程指示内核等待多个事件中的任何一个发生,并仅在有一个或是多个事件发生或经历一段指定的时间后才唤醒它。我们调用select告知内核对哪些描述字(就读、写或异常条件)感兴趣以及等待多长时间。我们感兴趣的描述字不局限于套接口,任何描述字都可以使用select来测试。

select函数原型:

#include<sys/select.h>#include<sys/time.h>int select (int maxfd , fd_set *readset ,fd_set *writeset, fd_set *exceptionset , const struct timeval * timeout);返回:就绪描述字的正数目,0——超时,-1——出错

select函数的参数介绍:maxfd表示待测试的描述字个数,其值应该为最大的描述字+1,中间的readset,writeset,exceptionset指定我们要让内核测试读、写、异常条件的描述字,最后一个参数告知内核等待所指定描述字中的任何一个就绪可花多长时间。

timeval结构:

struct timeval {long tv_sec; //secondslong tv_usec ; //microseconds}

timeval参数有三种可能值:1、NULL:代表永远等待下去,相当于完全阻塞。2、一个固定的值,代表等待一段固定的时间。3、timeval的属性值为0,表示根本不等待,检查描述字之后立即返回,也就是说事非阻塞的。

fd_set结构:

fd_set结构表示一个描述字集。它典型的应该以一个整数数组来表示,其中每个整数中的每一位对应一个描述字。关于fd_set有以下四个宏:

void FD_ZERO(fd_set *fdset); /* clear all bits in fdset */void FD_SET(int fd, fd_set *fdset); /* turn on the bit for fd in fdset */void FD_CLR(int fd, fd_set *fdset); /* turn off the bit for fd in fdset */int FD_ISSET(int fd, fd_set *fdset); /* is the bit for fd on in fdset ? */

select函数修改由指针readset,writeset,exceptionset所指向的描述字集,因而这三个参数都是值-结果参数。也就是说,在select函数执行过程中,会修改其中的值。调用该函数时,我们指定关心的描述字的值,该函数返回时,结果指示哪些描述字已就绪。该函数返回后,我们使用FD_ISSET来测试fd_set数据类型中的描述字。描述字集中任何与未就绪的描述字对应的位返回时均清为0.为此,每次重新调用select函数中,我们都得再次把所有描述字集合中的所关心的位置为1。这也是在稍候的通信例子里,我们设置resset和allset两个集合的原因所在。

select函数返回某个套接口就绪的条件:

select函数的通信例子:一个简单的TCP回射服务器程序

SelectServer.c: 使用select机制的服务器端程序

  1 #include <stdio.h>  2 #include <string.h>  3 #include <arpa/inet.h>  4 #include <netinet/in.h>  5 #include <sys/socket.h>  6 #include <sys/select.h>  7   8 const static int MAXLINE = 1024;  9 const static int SERV_PORT = 10001; 10  11 int main1() 12 { 13     int i , maxi , maxfd, listenfd , connfd , sockfd ; 14     /*nready 描述字的数量*/ 15     int nready ,client[FD_SETSIZE]; 16     int n ; 17     /*创建描述字集合,由于select函数会把未有事件发生的描述字清零,所以我们设置两个集合*/ 18     fd_set rset , allset; 19     char buf[MAXLINE]; 20     socklen_t clilen; 21     struct sockaddr_in cliaddr , servaddr; 22     /*创建socket*/ 23     listenfd = socket(AF_INET , SOCK_STREAM , 0); 24     /*定义sockaddr_in*/ 25     memset(&servaddr , 0 ,sizeof(servaddr)); 26     servaddr.sin_family = AF_INET; 27     servaddr.sin_port = htons(SERV_PORT); 28     servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 29  30     bind(listenfd, (struct sockaddr *) & servaddr , sizeof(servaddr)); 31     listen(listenfd , 100); 32     /*listenfd 是第一个描述字*/ 33     /*最大的描述字,用于select函数的第一个参数*/ 34     maxfd = listenfd; 35     /*client的数量,用于轮询*/ 36     maxi = -1; 37     /*init*/ 38     for(i=0 ;i<FD_SETSIZE ; i++) 39         client[i] = -1; 40     FD_ZERO(&allset); 41     FD_SET(listenfd, &allset); 42  43     for (;;) 44     { 45         rset = allset; 46         /*只select出用于读的描述字,阻塞无timeout*/ 47         nready = select(maxfd+1 , &rset , NULL , NULL , NULL); 48         if(FD_ISSET(listenfd,&rset)) 49         { 50             clilen = sizeof(cliaddr); 51             connfd = accept(listenfd , (struct sockaddr *) & cliaddr , &clilen); 52             /*寻找第一个能放置新的描述字的位置*/ 53             for (i=0;i<FD_SETSIZE;i++) 54             { 55                 if(client[i]<0) 56                 { 57                     client[i] = connfd; 58                     break; 59                 } 60             } 61             /*找不到,说明client已经满了*/ 62             if(i==FD_SETSIZE) 63             { 64                 printf("Too many clients , over stack .\n"); 65                 return -1; 66             } 67             FD_SET(connfd,&allset);//设置fd 68             /*更新相关参数*/ 69             if(connfd > maxfd) maxfd = connfd; 70             if(i>maxi) maxi = i; 71             if(nready<=1) continue; 72             else nready --; 73         } 74  75         for(i=0 ; i<=maxi ; i++) 76         { 77             if (client[i]<0) continue; 78             sockfd = client[i]; 79             if(FD_ISSET(sockfd,&rset)) 80             { 81                 n = read(sockfd , buf , MAXLINE); 82                 if (n==0) 83                 { 84                     /*当对方关闭的时候,server关闭描述字,并将set的sockfd清空*/ 85                     close(sockfd); 86                     FD_CLR(sockfd,&allset); 87                     client[i] = -1; 88                 } 89                 else 90                 { 91                     buf[n]='\0'; 92                     printf("Socket %d said : %s\n",sockfd,buf); 93                     write(sockfd,buf,n); //Write back to client 94                 } 95                 nready --; 96                 if(nready<=0) break; 97             } 98         } 99 100     }101     return 0;102 }

Client.c: 简单的客户端程序

 1 #include <stdio.h> 2 #include <string.h> 3 #include <arpa/inet.h> 4 #include <netinet/in.h> 5 #include <sys/socket.h> 6  7 #define MAXLINE 1024 8 int main() 9 {10     int sockfd ,n;11     char buf [MAXLINE];12     sockfd = socket(AF_INET,SOCK_STREAM ,0);13     struct sockaddr_in servaddr;14     memset(&servaddr, 0 ,sizeof(servaddr));    15     servaddr.sin_family = AF_INET;16     servaddr.sin_port = htons(10001);17     inet_pton( AF_INET ,"127.0.0.1" , &servaddr.sin_addr ) ;18 19     connect(sockfd,(struct sockaddr *)&servaddr , sizeof(servaddr));20     while(1)21     {22         printf("type some words ...\n");23         scanf("%s",buf);24         write(sockfd,buf,sizeof(buf));25         n = read(sockfd,buf,MAXLINE);26         printf("%d bytes received \n ",n);27         buf[n] = '\0';28         printf("%s\n",buf);29     }30     close(sockfd);31     return 0;32 }


总结:

在本文中,介绍了select函数在I/O复用中相关内容,并给出了一个典型的TCP反射程序的样例,使用select可以处理多个客户端的并发需求。在下一篇文章中,将会重点介绍另一种常见的I/O复用函数poll的使用。

转载于:https://www.cnblogs.com/coser/archive/2012/02/29/2373478.html

unix下网络编程之I/O复用(二)相关推荐

  1. Python网络编程之TCP服务器客户端(二)

    传输控制协议(官方术语为TCP/IP协议)是互联网的重要组成部分.TCP的第一个版本是在1974年定义的,它建立在网际层协议(IP)提供的数据包传输技术之上.TCP使得应用程序可以使用连续的数据流进行 ...

  2. linux网络编程之posix线程(二)

    继续接着上次的posix线程来学习: 回顾一下创建线程的函数: pthread_att_t属性变量是需要进行初始化才能够用的,一定初始化了属性变量,它就包含了线程的多种属性的值,那到底有哪些属性了,下 ...

  3. Python之路 - 网络编程之Socket

    Python之路 - 网络编程之Socket C/S架构 ? Socket ? 基于TCP ? 基于UDP ? Socket对象方法 ? C/S架构 ? 在网络通信中 , 一般是一方求一方应 , 求的 ...

  4. unix环境高级编程之 read与write 函数详解

    学习记录:unix环境高级编程之 read 与write  函数详解 备注:本博文非本人所写,本人觉得此文讲的非常地道通俗易懂,所以摘录在此以方便以后再次查看 read函数从打开的设备或文件中读取数据 ...

  5. Android 网络编程之HTTPS详解

    前言:HTTPS涉及相关的知识,总是很难的将其归纳总结起来,本文旨在带你学习详细的HTTPS相关知识点,看完本文后,你会了解到以下相关知识点: HTTPS的工作原理 HTTPS为什么要这样设计 密码学 ...

  6. Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解

    Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解 (1)sockaddr struct sockaddr { unsigned  short  sa_ ...

  7. 网络编程之socket

    网络编程之socket 看到本篇文章的题目是不是很疑惑,what is this?,不要着急,但是记住一说网络编程,你就想socket,socket是实现网络编程的工具,那么什么是socket,什么是 ...

  8. 网络编程+go+java_GO语言的进阶之路-网络编程之socket

    GO语言的进阶之路-网络编程之socket 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是socket; 在说socket之前,我们要对两个概念要有所了解,就是IP和端口 ...

  9. GO语言的进阶之路-网络编程之socket

    GO语言的进阶之路-网络编程之socket 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是socket; 在说socket之前,我们要对两个概念要有所了解,就是IP和端口 ...

最新文章

  1. 敏捷估算和计划的12条知道原则
  2. 小程序调用微信支付返回错误
  3. 华为交换机堆叠SVF助手(推荐)
  4. change事件判断ajax,jquery中change事件里面if语句失效
  5. Golang 检查元素在slice中是否存在 模仿Php实现arrary_In
  6. printf格式化输出类型
  7. 微信小程序—day01
  8. 英语口语 week12 Thursday
  9. 3条原则,16个小点,帮你写出一个优秀的对外接口!
  10. 洛谷P4548 [CTSC2006]歌唱王国(概率生成函数)
  11. 无刷直流电机换相原理
  12. android电视,手机控制,Android手机遥控电视:智能语音控制节目
  13. 程序员要实现财富自由,“出海”这条路该怎么走?
  14. 阿里巴巴集团急招职位
  15. Assimp库调用mtl加载obj模型
  16. UVa-12325宝箱
  17. 加拿大海运专线要多少天?有哪些物流方式?
  18. 山东哈斯精密机械有限公司
  19. 《MATLAB语音信号分析与合成(第二版)》:第7章 语音信号的减噪
  20. ”鼠标手“一族的福音---无线悬浮鼠标【转载】

热门文章

  1. TFS2008自定义过程模板之 Power Tools 工具篇
  2. 计算机基础教育德育教学,【家庭教育论文】计算机基础教学的德育教育(共2650字)...
  3. Linux操作系统Ubuntu部署GCC篇
  4. 作业——Windows核心编程学习手札系列之五
  5. tensorflow tf.nn.max_pool_with_argmax返回最大池化对应索引值
  6. Tensor2Tensor 踩坑记录
  7. ccf权限查询java_201612-3 ccf 权限查询
  8. STM32 FSMC 外部使用SRAM
  9. HPC System Design
  10. 8.3 matlab图形用户界面设计方法