UNIX环境高级编程——select和epoll的区别
select和epoll都用于监听套接口描述字上是否有事件发生,实现I/O复用
select(轮询)
#include <sys/select.h>
#include <sys/time.h>
int select (int maxfdpl, fd_set* readset, fd_set* writeset, fd_set* exceptset, const struct timeval* timeout)
调用时轮询一次所有描述字,超时时再轮询一次。如果没有描述字准备好,则返回0;中途错误返回-1;有描述字准备好,则将其对应位置为1,其他描述字置为0,返回准备好的描述字个数。
fd_set:整数数组,每个数中的每一位对应一个描述字,其具体大小有内核的FD_SETSIZE(1024)决定。
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
epoll(触发)
epoll对监听的每个fd都会有回调函数,当该fd上发生事件时,会调用对应的回调函数。
系列函数:
创建函数:
创建一个epoll句柄,size-监听套接字的数。当创建好epoll句柄后,会占用一个fd值,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
#include <sys/epoll.h>
int epoll_create(int size);
事件注册函数:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
第一个参数是epoll_create()的返回值;
第二个参数表示动作,用三个宏来表示:
- EPOLL_CTL_ADD:注册新的fd到epfd中,
- EPOLL_CTL_MOD:修改已经注册的fd的监听事件,
- EPOLL_CTL_DEL:从epfd中删除一个fd;
第三个参数是需要监听的fd;
第四个参数是告诉内核监听事件,struct epoll_event结构如下:
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t; struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
events可以是以下几个宏的集合:
- EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
- EPOLLOUT:表示对应的文件描述符可以写;
- EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
- EPOLLERR:表示对应的文件描述符发生错误;
- EPOLLHUP:表示对应的文件描述符被挂断;
- EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
- EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
使用如下:
struct epoll_event ev;
ev.data.fd=listenfd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
等待函数
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待事件的产生,参数events用来从内核得到事件集合。maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。
注意:某fd上发生事件后,其事件类型会被清空,所以如果下一个循环还要关注这个socket fd的话,则需要用epoll_ctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)来重新设置socket fd的事件类型。这时不用EPOLL_CTL_ADD,因为socket fd并未清空,只是事件类型清空。这一步非常重要。
实例
struct epoll_event ev, *events; for(;;) {
nfds = epoll_wait(kdpfd, events, maxevents, -1); for(n = 0; n < nfds; ++n) {
if(events[n].data.fd == listener) {
client = accept(listener, (struct sockaddr *) &local,
&addrlen);
if(client < 0){
perror("accept");
continue;
}
setnonblocking(client);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = client;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
fprintf(stderr, "epoll set insertion error: fd=%d\n",
client);
return -1;
}
} else {
do_use_fd(events[n].data.fd);
}
}
}
对比:
select - 如果同时建立很多连接,但只有少数事件发生,这种轮询会造成效率很低;频繁从内核拷贝、复制描述字;监听描述字受限于内核的FD_SETSIZE;
epoll - 这种回调触发式操作会保证效率;不需要频繁的拷贝;监听描述字没有限止,只与系统资源有关;epoll返回时已经明确的知道哪个sokcet fd发生了事件,不用再一个个比对。
UNIX环境高级编程——select和epoll的区别的更多相关文章
- UNIX环境高级编程——select、poll和epoll
一.select select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一. select的一个缺点在于单个进程能够监视的文件描述符的数量 ...
- (十一) 一起学 Unix 环境高级编程 (APUE) 之 高级 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (八) 一起学 Unix 环境高级编程 (APUE) 之 信号
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- 《UNIX环境高级编程(第3版)》
<UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...
- UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数
UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数 gethostname() getppername() getsockname() gethostbyname() ...
- (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- multiple definition of `err_sys' 《UNIX环境高级编程》
本文地址:http://www.cnblogs.com/yhLinux/p/4079930.html 问题描述: [点击此处直接看解决方案] 在练习<UNIX环境高级编程>APUE程序清单 ...
- unix环境高级编程基础知识之第二篇(3)
看了unix环境高级编程第三章,把代码也都自己敲了一遍,另主要讲解了一些IO函数,read/write/fseek/fcntl:这里主要是c函数,比较容易,看多了就熟悉了.对fcntl函数讲解比较到位 ...
- (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
随机推荐
- html下载excel模板
只需要href等于模板存放的路径即可 <a href="../../TempLate/Attitude.xlsx" class="easyui-linkbutton ...
- MySQL数据类型DECIMAL用法
MySQL DECIMAL数据类型用于在数据库中存储精确的数值.我们经常将DECIMAL数据类型用于保留准确精确度的列,例如会计系统中的货币数据. 要定义数据类型为DECIMAL的列,请使用以下语法: ...
- 安装redis 执行make命令时报错解决方法
一.未安装GCC 解决方法:执行yum install gcc-c++命令安装GCC,完成后再次执行make命令 yum install gcc-c++ Linux无法连接网络 http://www. ...
- FJUT第四周寒假作业之第一集,临时特工?(深度优先搜索)
原网址:http://210.34.193.66:8080/vj/Contest.jsp?cid=163#P2 第一集,临时特工? TimeLimit:1000MS MemoryLimit:128M ...
- R语言使用 multicore 包进行并行计算
R语言是单线程的,如果数据量比较大的情况下最好用并行计算来处理数据,这样会获得运行速度倍数的提升.这里介绍一个基于Unix系统的并行程序包:multicore. 我们用三种不同的方式来进行一个简单的数 ...
- Clojure新手入门
官方网站 clojure.org 环境安装 Java(JDK) Leiningen 编辑工具 Eclipse插件 -- Counterclockwise IntelliJ插件 -- Cursive E ...
- Node.js 字符串解码器
稳定性: 3 - 稳定 通过 require('string_decoder') ,可以使用这个模块.字符串解码器(StringDecoder)将缓存(buffer)解码为字符串.这是 buffer. ...
- Microsoft Dynamics 365 Developer Toolkit下载地址
下载,支持Visual Studio 2012, 2013, 2015
- 安卓高级Fresco图片框架的时候
Fresco:2015FaceBook推出的 及其强大 支持webp图片格式 和渐进式图片加载 中文文档 使用方法 引入依赖 点击查看具体教程 基本使用步骤 在布局中使用其标签 <com.fac ...
- Linux下一次数据仓库进行迁移记录
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52768613 前言:数据库每天的 ...