Linux高性能服务编程(I/O复用)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux高性能服务编程(I/O复用)相关的知识,希望对你有一定的参考价值。

I/O复用(本身是阻塞的)
网络程序需要使用I/O复用技术的情况:
1.客户端程序需要同时处理多个socket。
2.客户端需要同时处理用户输入和网络连接
3.TCP服务器要同时处理监听socket和连接socket
4.服务器要同时处理TCP请求和UDP请求
5.服务器要同时监听多个端口,或者处理多种服务。


linux下实现I/O复用的系统调用主要有select,poll和epoll

select系统调用的用途:在一段时间内,监听用户感兴趣的文件描述符上的可读,可写和异常等事件
select系统调用的原型:
#include<sys/select.h>
int select(int nfds,fd_set readfds,fd_set writefds,fd_set exceptfds,struct timeval timeout);
nfds参数指定被监听的文件描述符的总数,它通常被设置为select监听的所有文件描述符中的最大值加1,因为文件描述符是从0开始计数的
readfds,writefds,exceptfds参数分别指向可读,可写和一场事件对应的文件描述符集合
timeout参数用来设置select函数的超时时间,它是一个timeval结构体类型(微秒级)的指针,采用指针参数是因为内核将修改它以告诉应用程序select等待了多久

select成功时返回就绪(可读,可写,异常)文件描述符的总数。如果在超时时间内没有任何文件描述符就绪,select将返回0.select失败时返回-1并设置errno.如果
等待期间,程序接受信号,则select立即返回-1,并设置errno为EINTR。

poll系统调用:在制定时间内轮询一定数量的文件描述符,已测试其中是否有就绪者
poll原型:
#include<poll.h>
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
fds参数是一个pollfd结构类型的数组,它指定所有我们感兴趣的文件描述符上发生的可读,可写和异常等事件。
nfds参数指定被监听事件集合fds的大小,其类型nfds_t定义:typedef unsigned long int nfds_t;
timeout参数指定poll的超时值,单位是毫秒。当timeout为-1时,poll调用将永远阻塞,知道某个事件发生;当timeout为0时,poll调用立即返回

epoll系列系统调用:
epoll是linux特有的I/O复用函数
文件描述符(用来标识内核中的事件表)的创建有epoll_creat来完成:
#include<sys/epoll.h>
int epoll_creat(int size)
操作epoll内核时间表:
#include<sys/epoll.h>
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)
fd参数是要操作的文件描述符,op参数则制定操作类型(EPOLL_CTL_ADD(往事件表中注册fd上大的事件),EPOLL_CTL_MOD(修改fd上的注册事件),EPOLL_CTL_DEL(删除fd上的注册事件))
event参数指定事件,它是epoll_event结构指针类型

epoll_wait函数:
epoll系列系统调用的主要接口是epoll_wait函数,它在一段超时时间内等待一组文件描述符上的事件
#include<sys/epoll.h>
int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout)
该函数成功时返回就绪的文件描述符的个数,失败时返回-1并设置errno
maxevent参数指定最多监听多少个事件,它必须大于0


epoll对文件描述符的操作有两种模式
:LT(电平触发)模式(默认工作模式)和ET(边沿触发)模式(高效工作模式)
LT:当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序可以不立即处理该事件,当应用程序下一次调用epoll_wait时,epoll_wait还会再次向应用程序通告此事件,直到该事件被处理
ET:当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序必须立即处理该事件,因为后续的epoll_wait调用将不再向应用程序通知这一事件
EPOLLONESHOT事件


Select,poll和epoll的区别:

技术分享图片

I/O复用的高级应用一:非阻塞connect
Connect出错时的一种errno值:EINPROGRESS 这种错误发生在对非阻塞的socket调用connect,而连接又没有立即建立时。
I/O复用的高级应用二:聊天室程序
客户端功能:一是从标准输入终端读入用户数据,并将用户数据发送至服务器;二是往标准输出终端打印服务器程序发送给它的数据。
服务器的功能:接受客户数据,并把客户数据发送给每一个登陆到该服务区器上的客户端(数据发送者除外)
客户端:使用poll同时监听用户输入和网络连接,并利用splice函数将用户输入内容直接定向到网络连接上以发送之,从而实现数据零拷贝,提高程序执行效率。
服务器:使用poll同时监听socket和连接socket,并且使用牺牲空间换取时间的策略来提高服务器性能。
I/O复用的高级应用三:****同时处理TCP和UDP服务
超级服务xinetd:同时管理多个子服务,即监听多个端口
Xinetd采用/etc/xinetd.conf主配置文件和.etc.xinetd.d目录下的自配置文件来管理所有服务

以上是关于Linux高性能服务编程(I/O复用)的主要内容,如果未能解决你的问题,请参考以下文章

《Linux高性能服务器编程》学习总结——I/O复用

Linux高性能服务器编程I/O复用的高级应用

Linux高性能server编程——I/O复用

OpenResty搭建高性能服务端

OpenResty搭建高性能服务端

敲黑板!如何使用 OpenResty 搭建高性能服务端