OSX/iOS中多路I/O复用总结
2015-11-07 16:32
239 查看
OSX/iOS中多路I/O复用总结
http://www.tanhao.me/pieces/1777.html/在OSX/iOS中IO多路复用通常会选择select和kqueue,最近在尝试优化socket改进通信效率,所以总结一下两种模型的用法。
select
select是socket编程中非常重要的一个函数,并且也是兼容性最好的一种模型,在unix、linux、windows都有对应的实现,其函数原型是:1 2 3 4 5 6 7 | int select( int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, const struct timeval* timeout ); |
readfds:用于检查可读性的描述符集合,同时也是可读描述符的结果返回;
writefds:用于检查可写性的描述符集合,同时也是可写描述符的结果返回;
errorfds:用于检查异常的描述符集合,同时也是异常描述符的结果返回;
timeout:一个指向timeval结构的指针,用于决定select等待I/O的最长时间,它可以使select处于三种状态:
(1)第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
(2)第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
(3)第三,timeout的值大于0,这就是等待的超时时间,即 select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,>返回值同上述。
函数返回值:
负值:select错误
正值:某些文件可读写或出错
零值:等待超时,没有可读写或错误的文件
kqueue
kqueue是FreeBSD上的一种的多路复用机制,所以刚好能在OSX/iOS中使用。它是针对传统的select处理大量的文件描述符性能较低效而开发出来的。注册一批描述符>到kqueue以后,当其中的描述符状态发生变化时,kqueue将一次性通知应用程序哪些描述符可读、可写或出错了.kqueue模型最主要的函数就是kevent,它与select类似,提供向内核注册/反注册/修改事件和返回就绪事件或错误事件,函数原型为:
1 2 3 4 5 6 78 | int kevent( int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout ); |
changelist:注册/反注册事件的列表;
nchanges:changelist的个数;
eventlist:用于返回有事件发生的列表;
nevents:传入的eventlist的最大长度;
timeout:一个指向timeval结构的指针,指定超时时间;
函数返回值与select类似。
另外比较重要的就是struct kevent这个结构体了,它既是注册、反注册、修改事件的载体,也是事件返回的载体,它的原型为:
1 2 3 4 5 6 78 | struct kevent { uintptr_t ident; short filter; u_short flags; u_int fflags; intptr_t data; void *udata; }; |
ident:事件的id,实际应用中,一般设置为文件描述符;
filter:指定你希望内核用于ident成员的过滤器,我们可以指定EVFILT_READ(读状态)和EVFILT_READ(写状态);
flags:告诉内核应当对该事件在队列做何处理,我们可以指定EV_ADD(注册)、EV_DELETE(删除)、EV_ENABLE(开启,默认)、EV_DISABLE(停用),当flags用于eventlist返回事件时,可能包含EV_ERROR的掩码表示描述符错误事情;
fflags:用于指定你想让内核使用的特定于过滤器的标志;
data:用于保存任何特定于过滤器的数据,当filter指定为EVFILT_READ或EVFILT_READ时,data表示可读或可写的数据长度,当事件的描述符出错时,data表示错误>代码;
udata:data成员并不由kqueue使用,kqueue会把它的值不加修改地透传,用于类似于上下文。
总结
select的缺点:(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024(不同平台对FD_SETSIZE设定不一样)
(4)select接口使用并不灵活,无法分步提交集合,也无法将提交和查询分步,必须在一次调用中完成
(4)fd_set不能逆向转换为fd,需要再单独维护一份描述符的列表
而kqueue刚好能弥补这些缺陷,但却无法在其它平台使用
关于两种模型的实现示例下载:
SocketServer_select.zip
SocketServer_kqueue.zip
相关文章推荐
- (iOS)Storyboard 与 initWithCoder -- designated initializer小结
- IOS 的plis他 用法 小样
- IOS 的 plist方法 好记性不如看博客
- [转]iOS容易造成循环引用的三种场景,就在你我身边!
- ios常用的延时操作
- 解决IOS9友盟分享时明明安装了相关的分享软件,却提示未安装的问题
- iOS崩溃日志分析
- iOS 程序进入后台到底发生了什么?
- iOS-----使用AVAudioPlayer播放音乐
- ios9 XIB加载缓慢
- iOS之富文本
- iOS多线程编程之NSThread的使用
- iOS中常用的四种数据持久化方法简介
- iOS调试技巧之打印输出 -----A: (NSString *)description B:自定义LOG C:使用第三方插件快速打印
- iOS每日一读官方文档02
- JS与iOS之间的通信 iOS调用JS代码
- iOS: 在代码中使用Autolayout (1) - 按比例缩放和优先级
- iOS searchBar最近搜索结果的实现
- iOS(2)-内存管理
- iOS最全的常用正则表达式大全