缺点:创建线程会带来资源开销,能够现的并发量比较有限
没有数据到来时,可以让任务挂起,节省CPU资源开销,提升系统效率
fcntl
程序未接收到数据时一直执行,效率很低
只能绑定一个文件描述符用来读取数据
多个IO用一个函数接口监测
1、select监听的集合中的文件描述符有上限限制
2、select有内核层向用户层数据空间拷贝的过程,占用系统资源开销
3、select必须轮询检测产生事件的文件描述符
4、select只能工作在水平触发模式,无法工作在边沿触发(高速模式)
/* According to POSIX.1-2001, POSIX.1-2008 */
#include
/* According to earlier standards */
#include
#include
#include
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:监听文件描述符中是否有文件描述符变成ready状态
参数:
nfds:最大文件描述符的值+1;
readfds:读文件描述符的首地址
writefds:写文件描述符的首地址
exceptfds:其余文件描述符集合
timeout:等待的市场,NULL一直等待
返回值:成功返回文件描述符集合中文件描述符的个数,失败返回-1;
void FD_CLR(int fd, fd_set *set);
功能:将文件描述符fd从集合中清除
int FD_ISSET(int fd, fd_set *set);
功能:判断文件描述符fd是否能在集合中
void FD_SET(int fd, fd_set *set);
功能:将文件描述符fd加入到集合中
void FD_ZERO(fd_set *set);
将文件描述符集合清0;
写端:
- #include "head.h"
-
- int main(void)
- {
- int fd = 0;
- char tmpbuff[4096] = {0};
-
- mkfifo("/tmp/myfifo", 0777);
-
- fd = open("/tmp/myfifo", O_WRONLY);
- if (-1 == fd)
- {
- perror("fail to open");
- return -1;
- }
-
- while (1)
- {
- gets(tmpbuff);
- write(fd, tmpbuff, strlen(tmpbuff));
- }
- close(fd);
-
- return 0;
- }
读端:
- #include "head.h"
-
- int main(void)
- {
- int fd = 0;
- int flags = 0;
- char *pret = NULL;
- ssize_t nsize = 0;
- char tmpbuff[4096] = {0};
- fd_set rdfds;
- fd_set tmpfds;
- int ret = 0;
-
- mkfifo("/tmp/myfifo", 0664);
-
- fd = open("/tmp/myfifo", O_RDONLY);
- if (-1 == fd)
- {
- perror("fail to open");
- return -1;
- }
-
- FD_ZERO(&rdfds);//将文件描述符集合清0
- FD_SET(fd, &rdfds);//将文件描述符fd加入到文件描述符集合中
- FD_SET(0, &rdfds);//将文件描述符0加入到文件描述符集合中
-
- while (1)
- {
- tmpfds = rdfds;
- ret = select(fd+1, &tmpfds, NULL, NULL, NULL);
- if (-1 == ret)
- {
- perror("fail to select");
- return -1;
- }
-
- if (FD_ISSET(fd, &tmpfds))//判断文件描述符fd是否还在文件描述符集合中
- {
- memset(tmpbuff, 0, sizeof(tmpbuff));
- read(fd, tmpbuff, sizeof(tmpbuff));
- printf("FIFO:%s\n", tmpbuff);
- }
-
- if (FD_ISSET(0, &tmpfds))
- {
- memset(tmpbuff, 0, sizeof(tmpbuff));
- gets(tmpbuff);
- printf("STDIN:%s\n", tmpbuff);
- }
-
- }
-
- close(fd);
-
- return 0;
- }
结果:

1、poll监听的文件描述符没有上限的限制
2、有内核层向用户层数据空间拷贝的过程,占用系统资源开销
3、必须轮询检测产生事件的文件描述符
4、只能工作在水平触发模式,无法工作在边沿触发(高速模式)
#include
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能:监听文件描述符集合是否有事件发生
参数:
fds:监听文件描述符集合数组的空间首地址
nfds:监听文件描述符集合元素个数
timeout:等待的时间(-1 一直等待)
返回值:成功返回产生事件的文件描述符的个数,失败返回-1;
struct pollfd {
int fd; /* file descriptor */(监听的文件描述符)
short events; /* requested events */(要监听的事件)
POLLIN:是否可读
POLLOUT:是否可写
short revents; /* returned events */(实际产生的事件)
};
读端:
- #include "head.h"
-
- int main(void)
- {
- int fd = 0;
- int flags = 0;
- char *pret = NULL;
- ssize_t nsize = 0;
- char tmpbuff[4096] = {0};
- struct pollfd fds[2];
- int nready = 0;
-
- mkfifo("/tmp/myfifo", 0664);
-
- fd = open("/tmp/myfifo", O_RDONLY);
- if (-1 == fd)
- {
- perror("fail to open");
- return -1;
- }
-
- fds[0].fd = fd;
- fds[0].events = POLLIN;
- fds[1].fd = 0;
- fds[1].events = POLLIN;
-
- while (1)
- {
- nready = poll(fds, 2, -1);
- if (-1 == nready)
- {
- perror("fail to poll");
- return -1;
- }
-
- if (fds[0].revents & POLLIN)
- {
- memset(tmpbuff, 0, sizeof(tmpbuff));
- read(fd, tmpbuff, sizeof(tmpbuff));
- printf("FIFO:%s\n", tmpbuff);
- }
-
- if (fds[1].revents & POLLIN)
- {
- memset(tmpbuff, 0, sizeof(tmpbuff));
- gets(tmpbuff);
- printf("STDIN:%s\n", tmpbuff);
- }
- }
-
- close(fd);
- }
写端:
- #include "head.h"
-
- int main(void)
- {
- int fd = 0;
- char tmpbuff[4096] = {0};
-
- mkfifo("/tmp/myfifo", 0664);
-
- fd = open("/tmp/myfifo", O_WRONLY);
- if (-1 == fd)
- {
- perror("fail to open");
- return -1;
- }
-
- while (1)
- {
- gets(tmpbuff);
- write(fd, tmpbuff, strlen(tmpbuff));
- }
-
- close(fd);
-
- return 0;
- }
结果:

#include
int epoll_create(int size);
功能:创建一张内核事件表
参数:size:事件的个数
返回值:成功返回文件描述符,失败返回-1;
#include
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:维护epoll事件表
参数:
epfd:事件表的文件描述符
op:
EPOLL_CTL_ADD添加事件
EPOLL_CTL_MOD修改事件
EPOLL_CTL_DEL删除事件
fd:操作的文件描述符
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 */
};
返回值:成功0,失败-1;
events:

data:要操作的文件的文件描述符
#include
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
功能:监听事件表中的事件
参数:
epfd:事件表的文件描述符
events:存放实际产生事件的数组空间首地址
maxevents:最多存放事件的个数
timeout:设定监听的时间(超过该时间不再监听)-1一直监听直到有事件发生
返回值:
成功返回实际产生事件的文件描述符的个数
时间到达还没有事件产生返回0
失败返回-1
read.c
- #include "head.h"
-
- int main(void)
- {
- int fd = 0;
- int epfd = 0;
- struct epoll_event env;//epoll_ctl需要的事件的结构体
- int nready = 0;
- struct epoll_event retenv[2];
- int i = 0;
- ssize_t nsize = 0;
- char *pret = NULL;
- char tmpbuff[4096] = {0};
-
-
- mkfifo("/tmp/myfifo", 0664);
- fd = open("/tmp/myfifo", O_RDONLY);
- if (-1 == fd)
- {
- perror("fail to open");
- return -1;
- }
-
- /*创建一张2个事件的内核事件表*/
- epfd = epoll_create(2);
- if (epfd == -1)
- {
- perror("fail to create");
- return -1;
- }
-
- /*设置事件结构体的属性*/
- env.events = EPOLLIN;
- env.data.fd = fd;
- /*操作事件*/
- epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &env);
-
- env.events = EPOLLIN;
- env.data.fd = 0;
- epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &env);
-
- while (1)
- {
- /*监听事件表中的事件*/
- nready = epoll_wait(epfd, retenv, 2, -1);//第二个参数是存放实际产生事件的结构体, 最多存放的个数, 设置监听时间,-1一直监听直到有事件发生
- if (-1 == nready)
- {
- perror("fail to nready");
- return -1;
- }
-
- for (i = 0; i < nready; ++i)
- {
- if (retenv[i].data.fd == 0)//判断要操作的流是否为从终端输入
- {
- memset(tmpbuff, 0, sizeof(tmpbuff));
- gets(tmpbuff);
- printf("STDIN: %s\n", tmpbuff);
- }
-
- if (retenv[i].data.fd == fd)
- {
- memset(tmpbuff, 0, sizeof(tmpbuff));
- read(fd, tmpbuff, sizeof(tmpbuff));
- printf("FIFO: %s\n", tmpbuff);
- }
- }
- }
-
- close(fd);
-
- return 0;
- }
write.c
- #include "head.h"
-
- int main(void)
- {
- int fd = 0;
- char tmpbuff[4096] = {0};
-
- mkfifo("/tmp/myfifo", 0664);
-
- fd = open("/tmp/myfifo", O_WRONLY);
- if (-1 == fd)
- {
- perror("fail to open");
- return -1;
- }
-
- while (1)
- {
- gets(tmpbuff);
- write(fd, tmpbuff, strlen(tmpbuff));
- }
- close(fd);
-
- return 0;
- }
