进程间并发通信-IO多路复用

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);
}

1.2 运行结果

1.3 分析总结

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值