io多路复用监听有名管道的阻塞问题
尝试封装了一下,poll和有名管道读取的代码。
读取端使用O_RDONLY|O_NONBLOCK打开,写端是 只写 打开管道
问题:写端是处于阻塞状态,读端一直循环打印timout的情况,没有读取到管道数据
代码:
1.fifo.h
#ifndef __FIFO_H__
#define __FIFO_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#define FIFO_NAME "./fifo"
extern int readfifo(char *, int );
extern int writefifo(char *, int );
#endif
2.fifo.c
#include "fifo.h"
// 从管道读取数据
int readfifo(char *buffer, int sizebuff)
{
ssize_t rbytes;
int fd = 0;
fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK); // 打开管道文件, _oflag: 非阻塞只读
if (fd == -1)
{
perror("[ERROR] open():");
exit(EXIT_FAILURE);
}
rbytes = read(fd, buffer, sizebuff); // 从管道文件读数据
if (rbytes == -1)
{
perror("read():");
return -1;
}
close(fd);
return 0;
}
// 向管道发送数据
int writefifo(char *buffer, int sizebuff)
{
int fd = 0; // 文件描述符
int ret = 0; // 函数返回值
char _buffer[sizebuff];
ssize_t wbytes;
strcpy(_buffer, buffer);
/**
int access(const char *pathname,int mode)
参数:
pathname:表示要测试的文件的路径
mode:表示测试的模式可能的值有:
R_OK:是否具有读权限
W_OK:是否具有可写权限
X_OK:是否具有可执行权限
F_OK:文件是否存在
返回值:
若测试成功则返回0,否则返回-1
*/
ret = access(FIFO_NAME, F_OK); // 判断有名管道文件是否存在
if (ret == -1)
mkfifo(FIFO_NAME, 0644); // 创建管道文件
fd = open(FIFO_NAME, O_WRONLY); // 打开管道文件
if (fd == -1)
{
perror("[ERROR] open():");
exit(EXIT_FAILURE);
}
wbytes = write(fd, buffer, strlen(buffer) - 1);
if (wbytes == -1)
{
perror("write():");
return -1;
}
close(fd);
return 0;
}
3.io_poll.c
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include "fifo.h"
#define NFDS_POLLIN 1
struct pollfd *init_pollfd(int fdsarr[], nfds_t nfds, short int events)
{
struct pollfd *pfds = (struct pollfd *)calloc(nfds, sizeof(struct pollfd));
if (NULL == pfds)
{
fprintf(stdout, "init pollfd() faile.\n");
fflush(NULL);
exit(EXIT_FAILURE);
}
for (int i = 0; i < nfds; i++)
{
pfds[i].fd = fdsarr[i];
pfds[i].events = events;
}
return pfds;
}
int main(char argc, char *argv[])
{
int ret, i = 0;
char buffer[64] = {0};
int data_size = sizeof(buffer);
int fds_pollin[NFDS_POLLIN] = {0};
// 带参数数据发送端
if (argc == 2)
{
writefifo(argv[1], data_size);
fprintf(stdout, "wirte [ %s ] in fifo allready. ", argv[1]);
fflush(NULL);
return 0;
}
// 无参数据接收端
struct pollfd *pfds = init_pollfd(fds_pollin, NFDS_POLLIN, POLLIN);
for (;;)
{
ret = poll(pfds, NFDS_POLLIN, 1000);
if (ret == -1)
{
perror("[ERROR] poll(): ");
exit(EXIT_FAILURE);
}
else if (ret == 0)
{
printf("Timeout.\n");
}
else if (ret > 0)
{
for (i = 0; i < NFDS_POLLIN; i++)
{
// 判断返回的就绪事件是否为 POLLIN
if (pfds[i].revents & POLLIN)
{
readfifo(buffer, data_size); // 读取管道数据
printf("buffer : %s ", buffer);
}
}
}
}
free(pfds);
return 0;
}
27
收起
正在回答 回答被采纳积分+1
2回答
慕小白0101
2023-05-30 15:16:39
老师,请问我在使用select练习中为啥会出现perror打印 select(): Bad file descriptor

select() 练习代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#define FIFO_NAME "./fifo"
int openfifo()
{
int fd;
fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK); // 打开管道文件, _oflag: 非阻塞只读
if (fd == -1)
{
perror("[ERROR] open():");
exit(EXIT_FAILURE);
}
return fd;
}
/** 从管道读取数据
@param buffer 将有名管道中的数据写入buffer中
@param sizebuff 有名管道中sizebuff长度的数据写入到buffer中
*/
int readfifo(int fd, char *buffer, int sizebuff)
{
ssize_t rbytes;
rbytes = read(fd, buffer, sizebuff); // 从管道文件读数据
if (rbytes == -1)
{
perror("read():");
return -1;
}
close(fd);
return 0;
}
/** 向管道发送数据
@param buffer 将buffer中的数据写入有名管道中
@param sizebuff 写入sizebuff长度的数据到有名管道中
*/
int writefifo(char *buffer, int sizebuff)
{
int fd = 0; // 文件描述符
int ret = 0; // 函数返回值
ssize_t wbytes; // 写操作的返回值
/**
int access(const char *pathname,int mode)
参数:
pathname:表示要测试的文件的路径
mode:表示测试的模式可能的值有:
R_OK:是否具有读权限
W_OK:是否具有可写权限
X_OK:是否具有可执行权限
F_OK:文件是否存在
返回值:
若测试成功则返回0,否则返回-1
*/
ret = access(FIFO_NAME, F_OK); // 判断有名管道文件是否存在
if (ret == -1)
mkfifo(FIFO_NAME, 0644); // 创建管道文件
fd = open(FIFO_NAME, O_WRONLY); // 打开管道文件
if (fd == -1)
{
perror("[ERROR] open():");
exit(EXIT_FAILURE);
}
wbytes = write(fd, buffer, sizebuff);
if (wbytes == -1)
{
perror("write():");
return -1;
}
close(fd);
return 0;
}
int main(char argc, char *argv[])
{
int ret = 0;
int maxfd = 0;
fd_set readfds, tmpfds;
struct timeval tv = {3, 0}, tmp_tv;
char buffer[64] = {0};
int data_size = sizeof(buffer);
// 带参数数据发送端
if (argc == 2)
{
writefifo(argv[1], data_size);
fprintf(stdout, "wirte [ %s ] in fifo allready. \n", argv[1]);
fflush(NULL);
return 0;
}
int fd = openfifo();
maxfd = fd;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
for (;;)
{
tmp_tv = tv;
tmpfds = readfds;
ret = select(maxfd + 1, &tmpfds, NULL, NULL, &tmp_tv);
if (ret == -1)
{
perror("[ERROR] select(): ");
exit(EXIT_FAILURE);
}
else if (ret == 0)
{ // 超时返回
printf("Timeout.\n");
}
else if (ret > 0)
{
if (FD_ISSET(fd, &tmpfds))
{ // 判断是否在集合中
readfifo(fd, buffer, data_size);
fprintf(stdout, "buffer : %s \n", buffer);
fflush(NULL);
}
}
}
return 0;
}
无__名
2023-05-29 17:49:57
主要原因为读进程的文件描述符没有加入到poll 监听中 int fds_pollin[NFDS_POLLIN] = {0}; 初始化为0了,没有将打开管道的文件描述符加进入
这里可以进行如下修改
extern int openfifo(const char *pathname);
extern int readfifo(int fd,char *, int );
extern int writefifo(char *, int );
// 添加了一个函数
int openfifo(const char *pathname)
{
int fd;
fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK); // 打开管道文件, _oflag: 非阻塞只读
if (fd == -1)
{
return -1;
}
return fd;
}
// 从管道读取数据
int readfifo(int fd,char *buffer, int sizebuff)
{
ssize_t rbytes;
#if 0
int fd = 0;
fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK); // 打开管道文件, _oflag: 非阻塞只读
if (fd == -1)
{
perror("[ERROR] open():");
exit(EXIT_FAILURE);
}
#endif
rbytes = read(fd, buffer, sizebuff); // 从管道文件读数据
if (rbytes == -1)
{
perror("read():");
return -1;
}
close(fd);
return 0;
}
io_poll.c
include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include "fifo.h"
#define NFDS_POLLIN 1
struct pollfd *init_pollfd(int fdsarr[], nfds_t nfds,short int events)
{
struct pollfd *pfds = (struct pollfd *)calloc(nfds, sizeof(struct pollfd));
if (NULL == pfds)
{
fprintf(stdout, "init pollfd() faile.\n");
fflush(NULL);
exit(EXIT_FAILURE);
}
for (int i = 0; i < nfds; i++)
{
pfds[i].fd = fdsarr[i];
pfds[i].events = events;
}
return pfds;
}
int main(char argc, char *argv[])
{
int ret, i = 0;
char buffer[64] = {0};
int data_size = sizeof(buffer);
int fds_pollin[NFDS_POLLIN] = {0};
// 带参数数据发送端
if (argc == 2)
{
writefifo(argv[1], data_size);
fprintf(stdout, "wirte [ %s ] in fifo allready. ", argv[1]);
fflush(NULL);
return 0;
}
int fd;
fd = openfifo(FIFO_NAME);//获取读进程打开的文件
fds_pollin[0] = fd; //存储到文件描述符数组中
// 无参数据接收端
struct pollfd *pfds = init_pollfd(fds_pollin, NFDS_POLLIN, POLLIN);
for (;;)
{
ret = poll(pfds, NFDS_POLLIN, 1000);
if (ret == -1)
{
perror("[ERROR] poll(): ");
exit(EXIT_FAILURE);
}
else if (ret == 0)
{
printf("Timeout.\n");
}
else if (ret > 0)
{
for (i = 0; i < ret; i++)
{
// 判断返回的就绪事件是否为 POLLIN
if (pfds[i].revents & POLLIN)
{
readfifo(fd,buffer, data_size); // 读取管道数据
printf("buffer : %s ", buffer);
exit(0) ;
}
}
}
}
free(pfds);
return 0;
}
物联网/嵌入式工程师
- 参与学习 394 人
- 提交作业 23775 份
- 解答问题 1206 个
行业热门,政策风口,人才缺口极大,现在入场时机正好! 上千人检验,数轮迭代的硬核知识体系,软硬件通吃 保姆式教学+简历指导+1V1模拟面试+3次内推,助力轻松就业!
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星