我正在尝试将未命名的管道与其他一些文件描述符进行多路复用。
问题是管道文件描述符总是出现在select
的结果中。换句话说,事件循环从管道读取无限次。这是我想要做的事情的隐喻,以及实际发生的事情。
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
int main(){
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
int fdmax; // maximum file descriptor number
int pfd[2];
if(pipe(pfd)!=0) {cout<<"Unable to create a pipe.\n",exit(1);};
FD_SET(0, &master);
FD_SET(pfd[0],&master);
fdmax=pfd[0];
if(fork()){//Parent
for (;;){
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
for(int i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
int n;
char buff[200];
if (i==pfd[0]){
close(pfd[1]);
n=read(pfd[0],buff,sizeof(buff));
buff[n]=0;
cout<<"Read from pipe:"<<buff<<endl;
}else if(i==0){
n=read(0,buff,sizeof(buff));
buff[n]=0;
cout<<"Read from std:"<<buff<<endl;
}
}
}
}
}else{//Child
usleep(50000);
char buff[200]="This is a simple sample.";
close(pfd[0]);
write(pfd[1],buff,sizeof(buff));
close(pfd[1]);
exit(0);
}
}
答案 0 :(得分:1)
首先,read()
调用可以读取少于最后一个参数中指定的字节数,而ant id不会自动附加零字节终结符,因此您的接收代码可以轻松访问buff []中未初始化的内存之后(如果没有零字节)。 在调用read
时需要检查返回值,并且只使用缓冲区中的这么多字节。
然后,当select
集合中的任何文件描述符在后续读取时不会阻塞时,readfds
调用将返回。其中包括文件结束条件。这种情况可能发生在您的情况下,当分叉进程关闭其fd时。另见this SO question。
这可能是您遇到问题的原因吗?在调用read
时检查返回值会使您清楚,因为如果fd到达文件末尾,则读取返回零,如果fd到达文件末尾。
最后详细信息 - 仅在pfd[1]
中返回pfd[0]
后关闭readfds
没有多大意义。您应该在fork之后立即关闭它,因此只有在父进程中没有使用它时它才会在子进程中保持打开状态。