文档章节

Linux之I/O多路复用

o
 osc_wws45aot
发布于 2019/08/20 22:06
字数 1245
阅读 9
收藏 0

精选30+云产品,助力企业轻松上云!>>>

 I/O多路复用:单个线程可以同时处理多个I/O;

一、select:成功则返回已准备好的文件描述符个数,超时则返回0,出错则返回-1;

(1)头文件包含:#include <sys/select.h>、<unistd.h>、<sys/time.h>;

(2)select返回后集合fdset中只有事件发生了的fd对应的位被置为1,其他位都被清空为0,所以需要依次用FD_ISSET来判断是否被置为1即事件是否发生;

  • int select(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tvptr); 
  • int FD_ZERO(fd_set *fdset);---删除集合fdset中的所有文件描述符
  • int FD_SET(int fd, fd_set *fdset);---加入fd到集合fdset中
  • int FD_CLR(int fd, fd_set *fdset);---删除集合fdset中的fd
  • int FD_ISSET(int fd, fd_set *fdset);---判断fd为是否可读写
 1 #include <sys/select.h>
 2 #include <unistd.h>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     fd_set readset, writeset;
 7     int ret = 0;
 8     FD_ZERO(&readset);
 9     FD_ZERO(&writeset);
10     FD_SET(3, &readset);
11     FD_SET(5, &writeset);
12 
13     ret = select(6, &readset, &writeset, NULL, NULL);
14     switch (ret)
15     {
16     case -1: //error
17         break;
18     case 0: //timeout
19         break;
20     default: //success
21         if(FD_ISSET(3, &readset))
22         {
23             ;//read fd(3)
24         }
25         if(FD_ISSET(5, &writeset))
26         {
27             ;//write fd(5)
28         }
29         break;
30     }
31     return 0;
32 }
View Code

二、poll:成功则返回已准备好的文件描述符个数,超时则返回0,出错则返回-1;

(1)头文件包含:#include <poll.h>

(2)struct pollfd

  {

    int fd;

    short events; //input: interested event

    short revents; //output: occured event

  };

  • int poll(struct pollfd fds[], nfds_t nfds, int timeout);
 1 #include <poll.h>
 2 #define EVENTS_NUM 3
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     struct pollfd pfds[EVENTS_NUM];
 7     int ret = 0;
 8     
 9     pfds[0].fd = 10;
10     pfds[0].events = POLLIN;
11     pfds[1].fd = 11;
12     pfds[1].events = POLLOUT;
13     pfds[2].fd = 12;
14     pfds[2].events = POLLERR;
15 
16     ret = poll(pfds, EVENTS_NUM, -1);
17     switch (ret)
18     {
19     case -1: //error
20         break;
21     case 0: //timeout
22         break;
23     default: //success
24         for(int i = 0; i < EVENTS_NUM; i++)
25         {
26             if(pfds[i].revents & POLLIN)
27             {
28                 //read pfds[i].fd
29             }
30             else if(pfds[i].revents & POLLOUT)
31             {
32                 //write pfds[i].fd
33             }
34             else if(pfds[i].revents & POLLERR)
35             {
36                 //handle pfds[i].fd
37             }
38         }
39         break;
40     }    
41     return 0;
42 }
View Code

三、epoll:成功则返回已准备好的文件描述符个数,超时则返回0,出错则返回-1;

(1)头文件包含:#include <sys/epoll.h>,epoll是一种当文件描述符的内核读缓冲区非空的时候发出可读signal通知进程;当内核写缓冲区不满的时候发出可写signal通知进程的机制,即事件驱动的机制;

(2)LT:水平触发(Level Triggered),如果对就绪的文件描述符fd不做操作,则内核会一直通知直到fd被处理为止;默认值传统的select/poll也采用该机制

(3)ET:边缘触发(Edge Triggerred),不管有没有对就绪的文件描述符fd做操作,内核之通知一次;

  • int epoll_create(int size);
  • int epoll_ctl(int efpd, int op, int fd, struct epoll_event *event);
  • int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • int close(int epfd);
 1 #include <sys/epoll.h>
 2 #include <sys/eventfd.h> //eventfd,create a fd which is used to event-notify
 3 #define EVENT_NUM 3
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     int epfd, ret = 0;
 8     struct epoll_event tmpEvt, occuredEvts[20];  
 9 
10     epfd = epoll_create(256);
11     if(epfd < 0)
12     {
13         //error
14     }
15     for(int i = 0; i < EVENT_NUM; i++)
16     {
17         tmpEvt.data.fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
18         //tmpEvt.data.fd = i;
19         tmpEvt.events = EPOLLIN;
20         ret = epoll_ctl(epfd, EPOLL_CTL_ADD, i, &tmpEvt);
21         if(ret < 0)
22         {
23             //error
24         }
25     }
26     ret = epoll_wait(epfd, occuredEvts, EVENT_NUM, -1);
27     switch (ret)
28     {
29     case -1: //error
30         break;
31     case 0: //timeout
32         break;
33     default: //success
34         for(int i = 0; i < ret; i++) //traverse ret!!!!!!
35         {
36             if(occuredEvts[i].events & EPOLLIN)
37             {
38                 //read occuredEvts[i].data.fd
39             }
40             else if(occuredEvts[i].events & EPOLLOUT)
41             {
42                 //write occuredEvts[i].data.fd
43             }
44             else if(occuredEvts[i].events & EPOLLERR)
45             {
46                 //handle occuredEvts[i].data.fd
47             }
48         }
49         break;
50     }
51 
52     return 0;
53 }
View Code

四、select/poll/epoll之间的比较

1 select:需要将用户传入的集合拷贝到内核空间,然后遍历每个fd对应的设备状态,如果设备就绪就更新设备的状态并继续遍历;如果遍历完没有发现就绪的设备则挂起当前进程,直到有设备就绪或者超时,进程被唤醒后又要遍历每个fd;最大连接数1024或2048;
2 poll:和select机制类似,唯一不同的就是poll没有最大连接数的限制,因为poll内部是基于链表(传入数组头指针+长度)来存储的;

3 epoll:内核监听到某个fd就绪时,就会采用callback函数的机制把该fd放入到内核的就绪队列中,这样epoll_wait返回的时候就只需要遍历该就绪队列即可,而无需遍历所有的fd;内核用红黑树来管理传入的epfd即多个fd;

(1)没有最大连接数的限制,1G的内存可以监听10万个fd;

(2)当fd就绪时它只会遍历已经就绪的fd,时间复杂度O(1),而不会像select/poll那样线性遍历所有的fd,所以效率得到了提升;

(3)采用内存映射(mmap)技术,减少了内存拷贝的开销;

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
网络编程的模式

在网络程序开发中有两种模式Reactor模式和Proactor模式。Reactor模式一般用于同步I/O(包括网络)中,Proactor模式一 般用于异步I/O(包括网络)中。其实它们都属于I/O多路复用模式。I/O多路...

Fire_thief
2014/02/25
344
0
libevent解析(一)

在linux下开发网络服务程序一直在用libevent,对于我来说如果不把一个库的源代码看得八九不离十,我很难说服自己肆无忌惮地使用它。可能这是技术强迫症患者典型的症状。到今天我还是不敢说对...

Fire_thief
2014/06/13
184
0
IO模型演进

阻塞I/O模型 默认情况下,所有文件操作都是阻塞的。如下图所示:在进程空间中调用recvfrom,其系统调用直到数据包到达且被复制到应用进程的缓冲区中或者发生错误时才返回,在此期间一直会等待...

nextGood
2019/04/03
1
0
Redis 为什么使用单进程单线程方式也这么快(转载)

Redis 采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由 C 语言编写。官方提供的数据是可以达到100000+的 qps。这个数据不比采用单进程多线程的同样基于内存的 KV 数据库 Memcac...

osc_cam5rm2n
2018/07/25
1
0
Redis使用单进程单线程方式的优缺点分析

[转] http://www.syyong.com/db/Redis-why-the-use-of-single-process-and-single-threaded-way-so-fast.html Redis采用的是基于内存的采用的是单进程单线程模型的KV数据库,由C语言编写。官...

osc_z81q0lie
2018/01/25
2
0

没有更多内容

加载失败,请刷新页面

加载更多

dict.items()和dict.iteritems()有什么区别?

问题: Are there any applicable differences between dict.items() and dict.iteritems() ? dict.items()和dict.iteritems()之间是否有适用的区别? From the Python docs: 从Python文档中......

法国红酒甜
今天
20
0
R中“ =”和“ <-”赋值运算符有什么区别?

问题: What are the differences between the assignment operators = and <- in R? R中赋值运算符=和<-之间有什么区别? I know that operators are slightly different, as this example ......

fyin1314
今天
20
0
之间的区别 和

问题: I'm learning Spring 3 and I don't seem to grasp the functionality behind <context:annotation-config> and <context:component-scan> . 我正在学习Spring 3,并且似乎不太了解<......

javail
今天
15
0
业内首款,百度工业视觉智能平台全新亮相

本文作者:y****n 业内首款全国产化工业视觉智能平台——百度工业视觉智能平台亮相中国机器视觉展(Vision China),该平台所具有的核心AI能力完全自主可控,在质检、巡检等场景中具有高效、...

百度开发者中心
昨天
7
0
我们如何制作xkcd样式图? - How can we make xkcd style graphs?

问题: Apparently, folk have figured out how to make xkcd style graphs in Mathematica and in LaTeX . 显然,民间已经想出了如何在Mathematica和LaTeX中制作xkcd风格的图形。 Can we d......

富含淀粉
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部