1 select
1.1 源码示例
/*************************************************************************
> File Name: write.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年06月02日 星期日 14时50分23秒
************************************************************************/
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int fd=0;
char tmpbuff[4096]={0};
/* 1 创建有名管道 */
mkfifo("/tmp/myfifo",0664);
/* 2 打开有名管道 */
fd=open("/tmp/myfifo",O_WRONLY);
if(-1==fd)
{
perror("fail to open");
return -1;
}
/* 3 接收终端输入并写入管道文件描述符-向管道写数据 */
while(1)
{
fgets(tmpbuff,sizeof(tmpbuff),stdin);
write(fd,tmpbuff,strlen(tmpbuff));
}
/* 4 关闭管道 */
close(fd);
return 0;
}
/*************************************************************************
> File Name: read.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年06月02日 星期日 14时34分49秒
************************************************************************/
#include<stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
int fd=0;
fd_set rdfds;
fd_set tmpfds;
int ret=0;
char tmpbuff[4096]={0};
/* 1 创建有名管道 */
mkfifo("/tmp/myfifo",0664);
/* 2 打开有名管道 */
fd=open("/tmp/myfifo",O_RDONLY);
if(-1==fd)
{
perror("fail to open");
return -1;
}
/* 3 文件描述符集的操作 - 4个宏 - FD_ZERO(initialize)-FD_SET(create)-FD_CLR(delete)-FD_ISSET(retrieve) */
/* 3.1 初始化文件描述符集合 */
FD_ZERO(&rdfds);//清除文件描述符集合 - 初始化文件描述符集合
/* 3.2 增加文件描述符至文件描述符集合 */
FD_SET(fd,&rdfds);//添加文件描述符至文件描述符集
FD_SET(0,&rdfds);
/* 4 管道读(写) - 终端和管道-谁来数据就读谁 */
while(1)
{
/* 4.1 初始化监听文件描述符集合 */
tmpfds=rdfds;
/* 4.2 监听文件描述符集合 -> 监听多个文件描述符,直到有一个或者多个文件描述符准备进行某类IO操作 */
/*注意: 一旦监听到某个文件描述符准备进行IO操作,那么这个文件描述符监听前后状态就发生了变化 ( 非ready状态->ready状态 ),
* 所以要想一直对某个文件描述符进行监听,每次调用select之前都要重置该文件描述符状态为监听之前的状态(即非ready状态)*/
ret=select(fd+1,&tmpfds,NULL,NULL,NULL);
if(-1==ret)
{
perror("fail to select");
return -1;
}
/* 4.3 查询文件描述符集合中某个文件描述符状态是否发生改变 */
if(FD_ISSET(fd,&tmpfds))
{
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));
fgets(tmpbuff,sizeof(tmpbuff),stdin);
printf("stdin: %s\n",tmpbuff);
}
}
/* 5 关闭文件描述符 */
close(fd);
return 0;
}
1.2 运行结果
1.3 分析总结
2 poll
1.1 源码示例
/*************************************************************************
> File Name: write.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年06月02日 星期日 16时30分10秒
************************************************************************/
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int fd=0;
char tmpbuff[4096]={0};
/* 1 创建有名管道 */
mkfifo("/tmp/myfifo",0664);
/* 2 打开有名管道 */
fd=open("/tmp/myfifo",O_WRONLY);
if(-1==fd)
{
perror("fail to open");
return -1;
}
/* 3 接收终端输入并写入管道文件描述符-向管道写数据 */
while(1)
{
fgets(tmpbuff,sizeof(tmpbuff),stdin);
write(fd,tmpbuff,strlen(tmpbuff));
}
/* 4 关闭管道 */
close(fd);
return 0;
}
/*************************************************************************
> File Name: read.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年06月02日 星期日 16时30分10秒
************************************************************************/
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
int main(void)
{
int fd=0;
struct pollfd fds[2];
int fready=0;
char tmpbuff[4096]={0};
/* 1 创建有名管道 */
mkfifo("/tmp/myfifo",0664);
/* 2 打开有名管道 */
fd=open("/tmp/myfifo",O_RDONLY);
if(-1==fd)
{
perror("fail to open");
return -1;
}
/* 3 初始化文件描述符状态结构体数组*/
fds[0].fd=fd;//添加文件描述符至数组
fds[0].events=POLLIN;//修改文件描述符状态为 准备读
fds[1].fd=0;
fds[1].events=POLLIN;
/* 4 管道读(写) - 终端和管道-谁来数据就读谁 */
while(1)
{
/* 4.1 监听文件描述符状态结构体数组 */
fready=poll(fds,2,-1);//文件描述符数组(数组)-文件描述符个数(数组长度)-超时时间(-1 一直等)
if(-1==fready)
{
perror("fail to poll");
return -1;
}
/* 4.2 查询文件描述符状态 - 通过位掩码方式查询 - 置位 */
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));
fgets(tmpbuff,sizeof(tmpbuff),stdin);
printf("stdin: %s\n",tmpbuff);
}
}
/* 5 关闭管道 */
close(fd);
}
1.2 运行结果
1.3 分析总结
3 epoll
1.1 源码示例
/*************************************************************************
> File Name: write.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年06月02日 星期日 17时22分26秒
************************************************************************/
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int fd=0;
char tmpbuff[4096]={0};
/* 1 创建有名管道 */
mkfifo("/tmp/myfifo",0664);
/* 2 打开有名管道 */
fd=open("/tmp/myfifo",O_WRONLY);
if(-1==fd)
{
perror("fail to open");
return -1;
}
/* 3 接收终端输入并写入管道文件描述符-向管道写数据 */
while(1)
{
fgets(tmpbuff,sizeof(tmpbuff),stdin);
write(fd,tmpbuff,strlen(tmpbuff));
}
/* 4 关闭管道 */
close(fd);
return 0;
}
/*************************************************************************
> File Name: read.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年06月02日 星期日 17时22分26秒
************************************************************************/
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/epoll.h>
int main(void)
{
int fd=0;
int epfd=0;
struct epoll_event env;
int fready=0;
int i=0;
struct epoll_event retenv[2];
char tmpbuff[4096]={0};
/* 1 创建有名管道 */
mkfifo("/tmp/myfifo",0664);
/* 2 打开有名管道 */
fd=open("/tmp/myfifo",O_RDONLY);
if(-1==fd)
{
perror("fail to open");
return -1;
}
/* 3 创建内核事件表 - 并返回表头 */
epfd=epoll_create(2);//预期添加到事件表的文件描述符数量
if(-1==epfd)
{
perror("fail to epoll_create");
return -1;
}
/* 4 初始化内核epoll事件结构体 - 数据类型 -初始化事件结构体 */
env.events=EPOLLIN;//修改文件描述符状态为 准备读 - 事件状态 - 非ready态
env.data.fd=fd;//文件描述符 - 这里指有名管道
/* 5 操作内核epoll事件表 - EPOLL_CTL_ADD(增-fd)-EPOLL_CTL_DEL(删-fd)-EPOLL_CTL_MOD(改-fd事件) */
epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&env);//建立文件描述符fd及其对应的事件env,并将文件描述符fd添加到epoll事件表epfd中
env.events=EPOLLIN;
env.data.fd=0;
epoll_ctl(epfd,EPOLL_CTL_ADD,0,&env);//终端也将发生同样的事件(EPOLLIN),所以将终端(此指stdin)也加入至该内核事件表
/* 6 管道读(写) - 终端和管道-谁来数据就读谁 */
while(1)
{
/* 6.1 监听内核epoll事件表,并返回ready态的文件描述符数量 */
fready=epoll_wait(epfd,retenv,2,-1);//这里通过结构体数组retenv作为出参,将ready态的文件描述符带出-ready态
if(-1==fready)
{
perror("fail to epoll_wait");
return -1;
}
/* 6.2 遍历所有ready态的文件描述符 */
for(i=0;i<fready;i++)
{
/* 通过ready态文件描述符进一步确认是哪个文件描述符状态被置位 -
* 检测(类似于IO输入检测-key检测的思想-位掩码)-查询*/
if(retenv[i].data.fd==0)
{
memset(tmpbuff,0,sizeof(tmpbuff));
fgets(tmpbuff,sizeof(tmpbuff),stdin);
printf("stdin: %s\n",tmpbuff);
}
else if(retenv[i].data.fd==fd)
{
memset(tmpbuff,0,sizeof(tmpbuff));
read(fd,tmpbuff,sizeof(tmpbuff));
printf("fifo: %s\n",tmpbuff);
}
}
}
/* 6 关闭管道*/
close(fd);
}