Linux下的I/O多路复用select,poll,epoll浅析

转载:http://blog.csdn.net/u011573853/article/details/52105365

一,什么是I/O多路复用 
所谓的I/O多路复用在英文中其实叫 I/O multiplexing. 就是单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。) 
I/O multiplexing 这里面的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态(对应空管塔里面的Fight progress strip槽)来同时管理多个I/O流. 发明它的原因,是尽量多的提高服务器的吞吐量 
如图 
这里写图片描述 
二,多路复用的方式很多今天说一下select原理: 
select函数会等待,直到描述符句柄中有可用资源(可读、可写、异常)时返回,返回值是可用资源(可读/可写/异常等)描述符的个数(>0),0代表超时,-1代表错误。具体到内核大致是:当应用程序调用select() 函数, 内核就会相应调用 poll_wait(), 把当前进程添加到相应设备的等待队列上,然后将该应用程序进程设置为睡眠状态。直到该设备上的数据可以获取,然后调用wake_up()唤醒该应用程序进程。select每次轮训都会遍历所有描述符句柄。 
使用select模型的路径图如下 
这里写图片描述 
三,函数 
int select(int nfds, fd_set *readfds, fd_set *writefds, 
fd_set *exceptfds, struct timeval *timeout); 
nfds: 监控的文件描述符集里最大文件描述符加1,因为此参数会告诉内核检测前多少个文件描述符的状态 
readfds:监控有读数据到达文件描述符集合,传入传出参数 
writefds:监控写数据到达文件描述符集合,传入传出参数 
exceptfds:监控异常发生达文件描述符集合,如带外数据到达异常,传入传出参数 
timeout:定时阻塞监控时间,3种情况 
1.NULL,永远等下去 
2.设置timeval,等待固定时间 
3.设置timeval里时间均为0,检查描述字后立即返回,轮询 
struct timeval { 
long tv_sec; /* seconds */ 
long tv_usec; /* microseconds */ 
}; 
void FD_CLR(int fd, fd_set *set); 把文件描述符集合里fd清0 
int FD_ISSET(int fd, fd_set *set); 测试文件描述符集合里fd是否置1 
void FD_SET(int fd, fd_set *set); 把文件描述符集合里fd位置1 
void FD_ZERO(fd_set *set); 把文件描述符集合里所有位清0

select函数执行结果:执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,没有返回;当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。错误 
值可能为: 
EBADF 文件描述词为无效的或该文件已关闭 
EINTR 此调用被信号所中断 
EINVAL 参数n 为负值。 
ENOMEM 核心内存不足 
要想理解好select模型就要理解好fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。 
(1)执行fd_set set;FD_ZERO(&set);则set用位表示是0000,0000。 
(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1) 
(3)若再加入fd=2,fd=1,则set变为0001,0011 
(4)执行select(6,&set,0,0,0)阻塞等待 
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。 
基于上面的讨论,可以轻松得出select模型的特点: 
(1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务器上sizeof(fd_set)=128,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是128*8=1024。 
(2)将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个参数。 
(3)可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。

四,优缺点 
1,简单,可以在多种系统上使用 
2,select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开 
的文件描述符个数并不能改变select监听文件个数 
3,解决1024以下客户端时使用select是很合适的,但如果链接客户端过多,select采用的是轮询模型,会大大降低服务器响应效率,不应在select上投入更多精力 
五 案例 
server

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<ctype.h>#define MAXLINE 80
#define SERV_PORT 8000int main(int atgc,char*argv[])
{int i,maxi,maxfd,listenfd,connfd,sockfd;int nready,client[FD_SETSIZE];ssize_t n;fd_set rset,allset;char buf[MAXLINE];char str[INET_ADDRSTRLEN];socklen_t cliaddr_len;struct sockaddr_in  cliaddr,servaddr;listenfd  = socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));listen(listenfd,20);maxfd = listenfd;maxi = -1;for(i =0;i<FD_SETSIZE;i++){client[i] = -1;}FD_ZERO(&allset);FD_SET(listenfd,&allset);for(;;){rset = allset;nready = select(maxfd+1,&rset,NULL,NULL,NULL);if(nready < 0){printf("select error \n");exit(1);}if(FD_ISSET(listenfd,&rset)){cliaddr_len = sizeof(cliaddr);connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddr_len);printf("received from %s at PORT %d \n",inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),ntohs(cliaddr.sin_port));for(i=0;i<FD_SETSIZE;i++)if(client[i]<0){client[i]=connfd;break;}if(i==FD_SETSIZE){printf("too many clients\n");exit(1);}FD_SET(connfd,&allset);if(connfd>maxfd)maxfd = connfd;if(i>maxi)maxi = i;if(--nready==0)continue;}for(i=0;i<=maxi;i++){if((sockfd = client[i])<0)continue;if(FD_ISSET(sockfd,&rset)){if((n=read(sockfd,buf,MAXLINE))==0){close(sockfd);FD_CLR(sockfd,&allset);client[i]=-1;}else{int j;for(j=0;j<n;j++)buf[j]=toupper(buf[j]);write(sockfd,buf,n);}if(--nready ==0)break;}}}close(listenfd);return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

client

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#define MAXLINE 80
#define SERV_PORT 8000int main(int argc,char *argv[])
{struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd,n;sockfd = socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET,"192.168.1.103",&servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));while(fgets(buf,MAXLINE,stdin)!=NULL){write(sockfd,buf,strlen(buf));n = read(sockfd,buf,MAXLINE);if (n==0){printf("the other ha closed\n");break;}elsewrite(STDOUT_FILENO,buf,n);}close(sockfd);return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机组成原理(一)计算机系统概述

计算机组成原理&#xff08;一&#xff09;计算机系统概述一、计算机系统层次结构冯诺伊曼机计算机工作过程多级层次结构一、计算机系统层次结构 冯诺伊曼机 特点&#xff1a; 计算机由五大部件组成指令和数据以同等地位存于存储 器&#xff0c;可按地址寻访指令和数据用二进…

计算机组成原理(二)数据的表示和运算

计算机组成原理&#xff08;二&#xff09;数据的表示和运算一、BCD码二、奇偶校验码三、海明码四、循环冗余校验码&#xff08;CRC&#xff09;五、乘法运算原码乘法补码乘法六、除法运算原码除法补码除法七、浮点数的表示与运算浮点数的运算一、BCD码 组合式BCD码&#xff1…

Linux IO复用区别与epoll详解

转载&#xff1a;http://blog.csdn.net/hacker00011000/article/details/52160590 一、select、poll、epoll之间的区别总结[整理]   select&#xff0c;poll&#xff0c;epoll都是IO多路复用的机制。I/O多路复用就通过一种机制&#xff0c;可以监视多个描述符&#xff0c;一…

简单图和多重图

一、简单图    ① 不存在重复边&#xff1b;    ② 不存在顶点到自身的边&#xff1b; 二、多重图   ① 某两结点之间边数多于一条&#xff1b;   ② 允许顶点通过一条边和自己关联&#xff1b;

C++笔记:select多路复用机制

转载&#xff1a;http://blog.csdn.net/qdx411324962/article/details/42499535 函数作用&#xff1a; 系统提供select函数来实现多路复用输入/输出模型。select系统调用是用来让我们的程序监视多个文件句柄的状态变化的。程序会停在select这里等待&#xff0c;直到被监视的文件…

交叉编译执行应用程序出现:No such file or directory

问题分析 当我在arm板子上执行交叉编译过的程序的时候发现了这个错误。通过百度查询基本都是缺少32位库什么的,但是都不能解决问题。 然后我用ll指令&#xff0c;也排除了权限的原因。 我们用ldd指令发现&#xff0c;它不是动态执行的&#xff0c;虽然我们可以使用-static指…

select、poll、epoll 比较

转载&#xff1a;http://blog.csdn.net/dodo_328/article/details/39081183 1.Selet&#xff1a;本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。 缺点&#xff1a;1 单个进程可监视的fd数量被限制&#xff0c;因为受描述符集合fd_set限制&#xff0c;fd数量…

C库函数 File

C库函数常用的有&#xff1a;fopen, fclose, fread, fwrite, fgets, fputs, fscanf, fprintf, fseek, fgetc, fputc, ftell, feof, flush等&#xff0c; 当使用fopen打开一个文件时通常返回一个文件指针 FILE *fp。FILE类型是一个结构体&#xff0c;包含文件描述符&#xff08;…

Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

转载&#xff1a;http://blog.csdn.net/michael_kong_nju/article/details/43457393 写在开头&#xff1a; 在上一节中我们学习了一些基础的用来支持网络编程的API&#xff0c;包括“套接字的地址结构”、“字节排序函数”等。这些API几乎是所有的网络编程中都会使用的一些&…

C库函数与系统函数的关系

转载于:https://www.cnblogs.com/lr1402585172/p/10464933.html

Unix网络编程(六)高级I/O技术之复用技术 select

转载&#xff1a;http://blog.csdn.net/michael_kong_nju/article/details/44887411 I/O复用技术 本文将讨论网络编程中的高级I/O复用技术&#xff0c;将从下面几个方面进行展开&#xff1a; a. 什么是复用技术呢&#xff1f; b. 什么情况下需要使用复用技术呢&#xff1f; c. …

Ubuntu在vmware虚拟机无法上网的解决方法

http://blog.csdn.net/xueyushenzhou/article/details/50460183 在vmware中安装Ubuntu之后&#xff0c;我们希望基本的功能如上网、传输文件等功能都是可用的&#xff0c;但是经常遇到不能上网的情况。使用笔记本时&#xff0c;我们经常希望能通过无线网卡上网&#xff0c;但是…

IO 多路复用之poll总结

http://www.cnblogs.com/Anker/p/3261006.html IO多路复用之poll总结 1、基本知识 poll的机制与select类似&#xff0c;与select在本质上没有多大差别&#xff0c;管理多个描述符也是进行轮询&#xff0c;根据描述符的状态进行处理&#xff0c;但是poll没有最大文件描述符数量的…

C++项目中的extern C {}

http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html 引言 在用C的项目源码中&#xff0c;经常会不可避免的会看到下面的代码&#xff1a; 123456789#ifdef __cplusplusextern "C" {#endif/*...*/#ifdef __cplusplus}#endif它到底有什么用呢&#xff0c;…

C语言实现单链表(带头结点)的基本操作(创建,头插法,尾插法,删除结点,打印链表)

http://blog.csdn.net/xiaofeige567/article/details/27484137 C语言实现单链表&#xff08;带头结点&#xff09;的基本操作&#xff08;创建&#xff0c;头插法&#xff0c;尾插法&#xff0c;删除结点&#xff0c;打印链表&#xff09; [plain] view plaincopy #include<…

单向循环链表C语言实现

http://blog.csdn.net/morixinguan/article/details/51771633 我们都知道&#xff0c;单向链表最后指向为NULL&#xff0c;也就是为空&#xff0c;那单向循环链表就是不指向为NULL了&#xff0c;指向头节点&#xff0c;所以下面这个程序运行结果就是&#xff0c;你将会看到遍历…

web服务器原理

什么是web服务器&#xff1f; 在Mosaic浏览器&#xff08;通常被认为是第一个图形化的web浏览器&#xff09;和超链接内容的初期&#xff0c;演变出了“web服务器”的新概念&#xff0c;它通过HTTP协议来提供静态页面内容和图片服务。在那个时候&#xff0c;大多数内容都是静态…

(C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作

http://blog.csdn.net/fisherwan/article/details/19760681 上午写了下单向循环链表的程序&#xff0c;今天下午我把双向链表的程序写完了。其实双向链表和单向链表也是有很多相似的地方的&#xff0c;听名字可以猜到&#xff0c;每个节点都包含两个指针&#xff0c;一个指针指…

(C++版)链表(一)——实现单向链表创建、插入、删除等相关操作

http://blog.csdn.net/fisherwan/article/details/25557545 前段时间用C语言实现了链表的相关操作&#xff0c;但是发现当时挺清楚的&#xff0c;过了一段时间又忘的差不多了&#xff0c;所以现在打算用C再实现一遍&#xff0c;由于初次用C实现&#xff0c;存在错误的地方还望大…

(C语言版)链表(二)——实现单向循环链表创建、插入、删除、释放内存等简单操作

http://blog.csdn.net/fisherwan/article/details/19754585 昨天写了单向链表的代码&#xff0c;今天上午把单向循环链表的程序给敲完了。链表的相关操作一样的&#xff0c;包含链表的创建、判断链表是否为空、计算链表长度、向链表中插入节点、从链表中删除节点、删除整个链表…