非阻塞IO,
记录锁,
系统V流机制,
IO多路转接,
readv和writev
存储映射IO(mmap)
pipe/socketpair
pipe用来创建单向通信管道
socketpair用来创建双向通信管道.
int socketpair(int domain, int type, int protocol, int sv[2]);
dup/dup2
对输入文件描述符重定向
int dup(int oldfd);
int dup2(int oldfd, int newfd);
I/O多路转接之select
系统提供select函数实现多路复用输入输出模型.select系统调用让我们的程序监视多个文件句柄的状态变化.程序停在select等待,直到被监视的文件句柄有一个或者多个发生了状态改变.
文件句柄是一个整数,对应FILE*结构.
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
参数说明:
hfds是需要监视的最大文件描述符值+1;
rdset,wrset,exset分别对应需要检测的文件描述符集合,可写,可读,异常
struct timeval 结构用于描述一段时间长度,如果时间内,需要监视的描述符咩有事件发生则函数返回
宏分别提供了检测功能.
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
timeout参数:
NULL:表示select没有timeout,一直被阻塞,直到某个事件发生.
0;仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生.
特定时间值:如果指定时间内没有事件发生,select超时返回
函数返回值
执行成功返回描述符状态已改变的个数
如果返回0表示在描述词状态改变前已经超时timeout时间,没有返回;
当错误发生时返回-1,错误原因errno
select特点:
1可以监控的文件描述符个数取决于sizeof(fd_set)
2将fd加入select监控集合的同时,还要使用一个数据结构array保存放到select监控集合中的fd,
一是用于在select返回后,array作为源数据和FD_ISSET判断.
二是select返回后会把以前加入的但并无事件发生的fd清空,则每次都重新从array取得fd依次加入,扫描获取最大maxfd,用于第一个参数
3可见select模型必须在select前循环array(加入fd,取maxfd),select返回后循环array(判断FD_ISSET是否有事件发生)
select缺点
1)每次调用select都要把fd集合从用户态拷贝到内核态,这个开销在fd很多时很大
2)每次调用select都需要内核遍历传递进来的所有fd
3)select支持的文件描述符数量太小,默认1024
I/O多路转接之poll
不同于select使用三个位图表示三个fdset的方式,poll使用一个pollfd的指针来实现
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
结构包含要监视的event和发生的event,不再使用select"参数-值"传递方式.同时poll并没有最大数量限制
同select,poll返回后,需要轮询pollfd来获取就绪的描述符
I/O多路转接之epoll
为处理大批量句柄而改进的poll.
int epoll_create(int size);
int epoll_ctl(int epdf,int op, int fd, struct epoll_event* event);
事件注册函数,不同于select在监听事件时告诉内核要监听什么类型事件,而是在这里先注册要监听的事件类型
第一个参数为create的返回值
第二个参数表示动作:
EPOLL_CTL_ADD:注册新fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的监听事件
EPOLL_CTL_DEL:从epfd中删除一个fd
第三个参数是需要监听的fd
第四个参数告诉内核需要监听什么事:
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:可写
PRI:表示对应文件描述符有紧急的数据可读(这里应该表示有外来数据到来)
ERR:错误
HUP:表示对应的文件描述符被挂起
EPOLLET:将EPOLL设置为边缘触发模式(Edge Triggered),相对于LT
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要监听这个socket,需要从新将socket加入EPOLL队列\int epoll_wait(int epfd,struct epoll_event*events,int maxevenets,int timeout);
手机在epoll监控的事件已经发生的事件.参数events是分配好的epoll_event结构题数组,(event不可以是控制真,内核hafiz巴蜀据复制到event数组中,不会帮我们在用户态分配内存)maxevent告内之内核这个event有多大,这个maxevent的值不能超过epoll_creae时的size,参数timeout超时时间
如果函数调用成功,返回对应IO上准备好的文件描述符数目,返回0表示超时
epoll工作原理