具体实现机制:
1. select机制
1) 函数接口:
/* According to POSIX.1-2001 */
#include
/* According to earlier standards */
#includetime.h>
#include
#include
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数:
参数1:nfds表示的是集合中最大文件描述符+1;
参数2:readfds表示关心的读事件集合,不关心用NULL填充
参数3:writefds表示关心的写事件集合,不关心用NULL填充
参数4:exceptfds表示关心的其它事件集合,不关心用NULL填充
参数5:timeout用来设置阻塞事件
a, 设置为NULL,表示检测时一直阻塞,直到有事件准备就绪函数才返回
b, 设置结构体的值
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
1) 成员的值都0,非阻塞方式检测;
2) 成员值为非零,有阻塞时间。
返回值:
成功返回值准备就绪事件的个数;
返回0表示检测超时
失败返回-1,且修改errno的值。
void FD_CLR(int fd, fd_set *set); /* 将文件描述符fd从集合set中移除 */
int FD_ISSET(int fd, fd_set *set); /* 检测文件描述符fd是否在集合set,如果在返回非0,不在返回0 */
void FD_SET(int fd, fd_set *set); /* 将文件描述符fd添加到集合set中 */
void FD_ZERO(fd_set *set); /* 清空集合set */
2) 具体实现的思路:
a,创建读事件集合readfds,并清空集合
fd_set readfds;
FD_ZERO(&readfds);
b,将文件描述符listenfd添加到读事件集合readfds中;
FD_SET(listenfd, &readfds);
c,检测集合中是否有准备就绪的事件(阻塞方式检测,有事件准备就绪函数返回)
ret = select(nfds, &readfds, NULL, NULL, NULL);
d,得到准备就绪事件的文件描述符
for(fd = 0; fd < nfds; fd++) {
if (FD_ISSET(fd, &readfds)) {
e,对fd进IO操作。
}
}
3) 特征:
a,可以在一个任务中对多个阻塞io进程操作,谁先准备就绪,就操作谁。
b,如果操作事件不同,需要定义多个集合;
c,找到准备就绪的文件描述符的时候,需要从0遍历到最大的文件描述符。效率很低。
2. poll机制
相关函数接口:
#include
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数:
参数1:fds表示是IO操作的集合(数组)首元素的地址
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
events / revents:
POLLIN :读事件;
POLLOUT :写事件;
参数2:nfds表示表示fds中的有效项数;
参数3:timeout表示事件检测时间(是以ms为单位)
如果timeout = -1,表示以阻塞的方式去检测,没有事件准备就绪就一直阻塞,直到有事件准备就绪才返回。
如果timeout > 0 阻塞时间为timeout
如果timeout = 0 非阻塞方式;2) poll机制的具体是实现流程:
a,创建集合,并清空集合
struct pollfd fds[1024];
memset(fds, 0, sizeof(fds));
for (i = 0; i < 1024; i++)
fds[i].fd = -1;
b,将文件描述符listenfd及其对应的读写事件(POLLIN、POLLOUT)添加到集合fds中;
fds[0].fd = listenfd;
fds[0].events = POLLIN | POLLOUT;
nfds = 1;
while(1) {
c,调用poll函数,检测是否有准备就绪的事件,如果没有事件准备就绪,函数一直阻塞。如果有事件准备就绪函数返回;
ret = poll(fds, nfds, -1);d, 找到准备就绪事件的文件描述符;
for(i = 0; i < nfds; i++) {
if (fds[i].fd == -1)
continue;
fd = fds[i].fd;
if (fds[i].revents == POLLIN) {
e,处理读事件,IO读操作
} else if (fds[i].revents == POLLOUT) {
e,处理写事件,IO写操作
}
}
}优缺点:
1. 集合数减少,空间增大;
2. 效率提高;依然会对集合中所有元素进行遍历。(随着集合中元素的增多效率会下降)