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 人
- 提交作业 23319 份
- 解答问题 1185 个
行业热门,政策风口,人才缺口极大,现在入场时机正好! 上千人检验,数轮迭代的硬核知识体系,软硬件通吃 保姆式教学+简历指导+1V1模拟面试+3次内推,助力轻松就业!
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星