1.作用
①监视文件描述符的行为
②I/O多路转接技术:先构造一张有关描述符的列表,然后调用一个函数,知道这些描述符中的一个已准备好进行I/O时,给函数才返回。在返回时,它告诉进程哪些描述符已准备好可以进行I/O。
2.select函数
以事件为单位 监视文件描述符。 监视事件单一
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);//清空
①nfds你所指定的文件描述的中最大的那个+1
②fd_set *readfds, fd_set *writefds,fd_set *exceptfds 你所关心的可读 可写 异常的文件描述符
③最长等待时间 可以当做一个安全的sleep函数
不进行超时设置,就是死等,直到你感兴趣的事件发生
当函数返回的时候,这三个集合不会是你存在的监视现场,是当前存放结果的地方
监视结果和监视现场在同一个地方
对以前程序的改进 盲等
void relay(int fd1, int fd2)
{
int fd1_save;
int fd2_save;
struct fsm_st fsm12, fsm21;
fd_set rset, wset;//读集合 写集合
//不能确定哪个是阻塞哪个是非阻塞
fd1_save = fcntl(fd1,F_GETFL);
fcntl(fd1, F_SETFL, fd1_save|O_NONBLOCK);
fd2_save = fcntl(fd2,F_GETFL);
fcntl(fd2, F_SETFL, fd2_save|O_NONBLOCK);
fsm12.State = STATE_R;
fsm12.sfd = fd1;
fsm12.dfd = fd2;
fsm21.State = STATE_R;
fsm21.sfd = fd2;
fsm21.dfd = fd1;
while(STATE_T != fsm12.State || STATE_T != fsm21.State)
{
//布置监视任务
FD_ZERO(&rset);FD_ZERO(&wset);
if(STATE_R == fsm12.State)
{
FD_SET(fsm12.sfd, &rset);
}
if(STATE_W == fsm12.State)
{
FD_SET(fsm12.dfd, &wset);
}
if(STATE_R == fsm21.State)
{
FD_SET(fsm21.sfd, &rset);
}
if(STATE_W == fsm21.State)
{
FD_SET(fsm21.dfd, &wset);
}
//监视
if(select(Max(fd1, fd2)+1, &rset, &wset, NULL, NULL)<0)
{
if(EINTR == errno)
continue;
perror("select()");
exit(1);
}
//根据监视结果 来推动状态机
if(FD_ISSET(fd1, &rset) || FD_ISSET(fd2, &wset))
fsm_driver(&fsm12);
if(FD_ISSET(fd1, &wset) || FD_ISSET(fd2, &rset))
fsm_driver(&fsm21);
}
fcntl(fd1, F_SETFL, fd1_save);
fcntl(fd2, F_SETFL, fd2_save);
}
3.poll
wait for some event on a file descriptor
以文件描述符为单位,组织事件
感兴趣的事件和发生的事件已经分开存放了
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
①struct pollfd *fds 不是给他一个结构体,而是给一个结构体数组的起始地址
②nfds指定数组的大小
③超时时间
void relay(int fd1, int fd2)
{
int fd1_save;
int fd2_save;
struct fsm_st fsm12, fsm21;
struct pollfd pfd[2];
//不能确定哪个是阻塞哪个是非阻塞
fd1_save = fcntl(fd1,F_GETFL);
fcntl(fd1, F_SETFL, fd1_save|O_NONBLOCK);
fd2_save = fcntl(fd2,F_GETFL);
fcntl(fd2, F_SETFL, fd2_save|O_NONBLOCK);
fsm12.State = STATE_R;
fsm12.sfd = fd1;
fsm12.dfd = fd2;
fsm21.State = STATE_R;
fsm21.sfd = fd2;
fsm21.dfd = fd1;
pfd[0].fd = fd1;
pfd[1].fd = fd2;
while(STATE_T != fsm12.State || STATE_T != fsm21.State)
{
//布置监视任务
pfd[0].events = 0;
pfd[1].events = 0;
if(STATE_R == fsm12.State)
{
pfd[0].events |= POLLIN;
}
if(STATE_W == fsm21.State)
{
pfd[0].events |= POLLOUT;
}
if(STATE_R == fsm21.State)
{
pfd[1].events |= POLLIN;
}
if(STATE_W == fsm12.State)
{
pfd[1].events |= POLLOUT;
}
//监视
while(poll(pfd, 2 ,-1) < 0)
{
if(EINTR == errno)
continue;
perror("select()");
exit(1);
}
//根据监视结果 来推动状态机
if(pfd[0].revents & POLLIN || pfd[1].events & POLLOUT)
fsm_driver(&fsm12);
if(pfd[1].revents & POLLIN || pfd[0].events & POLLOUT )
fsm_driver(&fsm21);
}
fcntl(fd1, F_SETFL, fd1_save);
fcntl(fd2, F_SETFL, fd2_save);
}
4.epoll
SYNOPSIS
#include <sys/epoll.h>
DESCRIPTION
The epoll API performs a similar task to poll(2):
monitoring multiple file descriptors to see if I/O is possible on
any of them. The epoll API can be used either as an edge-triggered
or a level-triggered interface and scales well to large numbers
of watched file descriptors. The following system calls are provided
to create and manage an epoll instance:
* epoll_create(2) creates an epoll instance and returns a file
descriptor referring to that instance. (The more recent
epoll_create1(2) extends the functionality of epoll_create(2).)
* Interest in particular file descriptors is then registered via
epoll_ctl(2). The set of file descriptors currently registered on
an epoll instance is sometimes called an epoll set.
* epoll_wait(2) waits for I/O events, blocking the calling thread
if no events are cur‐rently available.
epoll_create
int epoll_create(int size);
size随意给一个正数
原来的poll是自己管理一个数组,现在是内核在帮你管理
epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *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 */
};
刚才获得的实例,操作, 针对哪个文件描述符,什么事件
操作是针对这个文件描述符的哪个事件
epoll_wait
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);