一、 select的工作机制

select,是基于内核函数sys_poll实现的,有文件描述符(1024)的限制大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,开销随着文件描述符数量的增加而线性增大。(大量并发,少量活跃率较低)
应用层与内核的交互如下图:

select需要驱动程序的支持,驱动程序实现fops内的poll函数。select通过每个设备文件对应的poll函数提供的信息判断当前是否有资源可用(如可读或写),如果有的话则返回可用资源的文件描述符个数,没有的话则睡眠,等待有资源变为可用时再被唤醒继续执行。
1. select的睡眠过程
支持阻塞操作的设备驱动通常会实现一组自身的等待队列如读/写等待队列用于支持上层(用户层)所需的BLOCK或NONBLOCK操作。当应用程序通过设备驱动访问该设备时(默认为BLOCK操作),若该设备当前没有数据可读或写,则将该用户进程插入到该设备驱动对应的读/写等待队列让其睡眠一段时间,等到有数据可读/写时再将该进程唤醒。

select就是巧妙的利用等待队列机制让用户进程适当在没有资源可读/写时睡眠,有资源可读/写时唤醒。下面我们看看select睡眠的详细过程。

select会循环遍历它所监测的fd_set(一组文件描述符(fd)的集合)内的所有文件描述符对应的驱动程序的poll函数。驱动程序提供的poll函数首先会将调用select的用户进程插入到该设备驱动对应资源的等待队列(如读/写等待队列),然后返回一个bitmask告诉select当前资源哪些可用。当select循环遍历完所有fd_set内指定的文件描述符对应的poll函数后,如果没有一个资源可用(即没有一个文件可供操作),则select让该进程睡眠,一直等到有资源可用为止,进程被唤醒(或者timeout)继续往下执行。(该函数会阻塞)

2.select的唤醒
唤醒进程的过程通常是在所监测文件的设备驱动内实现的,驱动程序维护了针对自身资源读写的等待队列。当设备驱动发现自身资源变为可读写并且有进程睡眠在自身资源的等待队列上时,就会唤醒自身资源等待队列上的进程。

3.select的函数

int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
功能:监听多个文件描述符的属性变化(读,写,异常)void FD_CLR(int fd,fd_set *set);  //把文件描述符集合里fd清0int FD_ISSET(int fd,fd_set *set); //测试文件描述符集合里fd是否置1void FD_SET(int fd,fd_set *set); //把文件描述符集合里fd位置1void FD_ZERO(fd_set *set);  //把文件描述符集合里所有位清0
参数:nfds:最大文件描述符+1readfds:需要监听的读的文件描述符存放集合writefds:需要监听的写的文件描述符存放集合  exceptfds:需要监听的异常的文件描述符存放集合 NULLtimeout:多长时间监听一次  固定的时间,限时等待 NULL永久监听struct timeval{long tv_sec; //秒long tv_usec; //微妙};返回值:返回的是变化的文件描述符的个数注意:变化的文件描述符会存放在监听的集合中,未变化的文件描述符会被删除

二、select的编程

程序实例:select实现的并发服务器,接收客户端发送的内容并显示,并且在返回给客户端

#define MAX_SIZE 1024
int main(int argc,char *argv[])
{char buf[MAX_SIZE];   int n;int sockfd=socket(AF_INET,SOCK_STREAM,0);sockaddr_in addr;memset(&addr,0,sizeof(addr));addr.sin_addr.s_addr=0;addr.sin_family=AF_INET;addr.sin_port=htons(8888);bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));listen(sockfd,128);fd_set rfds,rset,wfds,wset;FD_ZERO(&rfds);FD_SET(sockfd,&rfds);FD_ZERO(&wfds);int max_fd=sockfd;while (1){rset=rfds;wset=wfds;int ready=select(max_fd+1,&rset,&wset,NULL,NULL);if(FD_ISSET(sockfd,&rset)){struct sockaddr_in clientaddr;socklen_t len=sizeof(clientaddr);int cfd=accept(sockfd,(struct sockaddr *)&clientaddr,&len);FD_SET(cfd,&rfds);/**/if(cfd>max_fd)  max_fd=cfd;if(--ready==0)  continue;}for(int i=sockfd+1;i<=max_fd;i++){if(FD_ISSET(i,&rset)){n=recv(i,buf,MAX_SIZE,0);if(n>0){buf[n]='\0';printf("recv msg from client: %s\n",buf);FD_SET(i,&wfds);}else if(n==0){close(i);FD_CLR(i,&rfds);continue;}if(--ready==0)  break;}else if(FD_ISSET(i,&wset)){printf("n的个数 %d\n",n);send(i,buf,n,0);**FD_CLR(i,&wfds);**//非常重要// FD_SET(i,&rfds);}}}close(sockfd);return 0;
}

此程序中把recv()和send()进行分开,读和写不是在一次select监听后统一执行的啊,是分别调用一次select各自执行的啊。读和写事件的发生是调用了两次select啊(即select的执行次数一定为偶数),注意服务器send完数据后一定要把fd_set集合的文件描述符清0FD_CLR(i,&wfds); (select监听可写事件时,只要连接未断开,文件描述符开着,监听到的文件描述符就一直可写。当select函数返回的时候,writefds将清除其中不可写的文件描述符,只留下可写的文件描述符。如果send完数据,不把写集合里面的文件描述符清0,就一直可写,一直send,陷入了死循环)

三、select的优缺点

优点:跨平台
缺点:
文件描述符1024的限制 由于FD_SETSIZE的限制
只是返回变化的文件描述符的个数,具体那个变化需要遍历**(集合的文件描述符用完(断开连接)会被回收,因此集合文件描述符不一定是按着顺序依次递增)**
每次都需要将需要监听的文件描述符集合由应用层拷贝到内核
大量并发,少量活跃率低

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:服务器课程

Linux网络编程 ——Select机制相关推荐

  1. linux网络编程--select/poll/epoll 详解

    目录 参考链接 epoll函数 close epoll event EL/LT ET Edge Trigger 边沿触发工作模式 LT Level Trigger 水平触发工作模式 epoll 源码解 ...

  2. linux网络编程(三)select、poll和epoll

    linux网络编程(三)select.poll和epoll 一.为什么会有多路I/O转接服务器? 二.select 三.poll 三.epoll 一.为什么会有多路I/O转接服务器? 为什么会有多路I ...

  3. 【Linux网络编程】并发服务器之select模型

    00. 目录 文章目录 00. 目录 01. 概述 02. I/O复用技术概述 03. select模型服务器实现思路 04. select模型服务器实现 05. 附录 01. 概述 服务器设计技术有 ...

  4. Linux网络编程---I/O复用模型之select

    https://blog.csdn.net/men_wen/article/details/53456435 Linux网络编程-I/O复用模型之select 1. IO复用模型 IO复用能够预先告知 ...

  5. Linux网络编程——黑马程序员笔记

    01P-复习-Linux网络编程 02P-信号量生产者复习 03P-协议 协议: 一组规则. 04P-7层模型和4层模型及代表协议 分层模型结构: OSI七层模型: 物.数.网.传.会.表.应TCP/ ...

  6. Linux网络编程——千峰物联网笔记

    B站视频:千峰物联网学科linux网络编程 网址:https://www.bilibili.com/video/BV1RJ411B761?p=1 目录 第一章:计算机网络概述 1.1计算机网络发展简史 ...

  7. 计算机网络(二)Linux网络编程

    layout: post title: 计算机网络(二)Linux网络编程 description: 计算机网络(二)Linux网络编程 tag: 计算机网络 文章目录 资源共享 Linux高性能服务 ...

  8. Proxy源代码分析--谈谈如何学习linux网络编程

    Linux是一个可靠性非常高的操作系统,但是所有用过Linux的朋友都会感觉到,Linux和Windows这样的"傻瓜"操作系统(这里丝毫没有贬低Windows的意思,相反这应该是 ...

  9. 【Linux】Linux网络编程(含常见服务器模型,下篇)

    上一篇文章:[Linux]Linux网络编程(含常见服务器模型,上篇). 高级嵌套字函数 前面介绍的一些函数(read.write等)都是网络程序里最基本的函数,也是最原始的通信函数.下面介绍一下几个 ...

  10. 很全的linux网络编程技巧

    注:作者王晓,本人认为总结得很好,故记之,绝无侵权之意. 本文转自:https://www.cnblogs.com/jfyl1573/p/6476607.html 看到好文章想留做自己学习,如有侵权, ...

最新文章

  1. HTML5之Viewport详解
  2. learning ddr pagesize calculate
  3. [摘自MSDN] ASP.Net2.0学习 [2] 主题 1 :ASP.NET 主题和外观概述
  4. Android UI-实现底部切换标签(fragment)
  5. PCB制图 | Altium Designer 20下载与安装
  6. [JavaScript] Canvas 实现的签字板
  7. 基于NXP i.MX 8M Plus处理器的核心板和开发板有什么功能
  8. Linux系统的PAM模块认证文件含义说明总结
  9. lineageos信号叉号_安卓手机刷lineageOS后电信卡不能通话解决办法
  10. android有多个活动,Android活动一探究竟
  11. Python操作表格
  12. python 手动读取cifar10_如何用python解析cifar10数据集图片
  13. 贵卅大学计算机研究生院导师,贵州大学机械工程学院研究生导师:罗绍华
  14. 大数据杂谈篇:认识大数据生态(个人心得分享)
  15. VUI设计--一些自己认为的原则
  16. 乔布斯在困境中的关键一战
  17. 2020.10.25 删除文本的标点并转换成列表
  18. 幸运6怎么喝到幸运7_幸运的休息并说是
  19. SimpleDateFormat小坑
  20. 用python提取PDF表格内容保存到excel

热门文章

  1. Ubuntu 20.04.2 LTS安装微信(wine)
  2. 操作系统-------------------内存空间的分配方式(连续分配和非连续分配和虚拟存储技术)
  3. 思维导图----百度百科
  4. adb shell 小米手机_Ubuntu下adb连接小米手机
  5. nowcoder20072 [HNOI2009]图的同构
  6. SU(Seismic Unix)之sgy格式与su格式相互转化
  7. ElasticSearch安装中文分词器IK和拼音分词器
  8. PHP 图片上文字排版,文字输出至图片的排版有关问题
  9. WGS84转GCj02
  10. 经纬度转换 gcj02转wgs84