当作家来来去去时,从命名管道重新读取
我遇到了一个问题,我必须从命名管道读取数据。我必须处理写作者到命名管道的情况,但我需要在整个应用程序中保持相同的管道畅通。当作家来来去去时,从命名管道重新读取
我总结了下面的代码。
int main(int c, char *v[])
{
int rfd;
if ((rfd = open(PIPENAME, O_RDONLY | O_NONBLOCK)) < 0)
{
perror("open");
return 1;
}
char buffer[ 1024000 ];
// used to give select an upper bound on number of fds
int nfd = rfd + 1;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(rfd, &rfds);
while(true)
{
int nr = select(nfd, &rfds, NULL, NULL, NULL);
if (nr < 0)
{
perror("select");
break;
}
if (FD_ISSET(rfd, &rfds))
{
//std::cout << "RFD SET" << std::endl;
// Ok, we have data we can read
int nread = read(rfd, buffer, sizeof(buffer));
if (nread < 0)
{
perror("read");
break;
}
else if (nread == 0)
{
std::cout << "read 0" << std::endl;
}
else
{
std::cout << "read " << nread << " bytes" << std::endl;
}
}
}
close(rfd);
return 0;
}
我的问题是,第一进程写入命名管道和断开(关闭)后,它的结束,我的程序不会在选择阻塞。它实际上具有rfd集合,并且读取返回零字节,在紧密循环中读取。
我需要rfd处于NON_BLOCKING模式,否则打开将会阻塞,直到出现一个编辑器。
我试过用fcntl设置为BLOCKING模式,但那也不管用。
我对管道语义的有限理解让我觉得我需要清除管道上的EOF状态,以便选择现在会阻塞。但是,我不知道如何做到这一点。
我把自己放在你的集体智慧:) 马克。
好的,我想出了一个解决方案,但我并不满意。如果你问我,这有点像是“砸碎坚果的锤子”。
.....
else if (nread == 0)
{
std::cout << "read 0" << std::endl;
FD_ZERO(&rfds);
close(rfd);
if ((rfd = open(PIPENAME, O_RDONLY | O_NONBLOCK)) < 0)
{
perror("re-open");
break;
}
FD_SET(rfd, &rfds);
nfd = std::max(wfd, rfd) + 1;
}
else
.....
基本上,我关闭并重新打开管道。
我仍然欢迎更好的解决方案。
您是否试过在非阻塞模式下打开fds,当您的read()
返回EWOULDBLOCK
/EAGAIN
时,在fd?上做clearerr()
?
clearerr仅适用于FILE *而非fd。 – ScaryAardvark 2010-01-19 10:05:41
是的。我能看到的唯一方法是'fdopen'为fd获得'FILE *',然后在''上使用'clearerr()'。 – 2010-01-19 10:08:45
问题是,虽然你永远不能关闭FILE *,因为那会关闭底层fd。我上面的例子假设我打开了管道,但实际上我希望解决方案即使交给管道fd也能工作。最终在这些情况下,使用fdopen/clearerr会导致内存泄漏,因为您不知道FILE *传递给您的方式,您既不能释放()也不能将其删除。 – ScaryAardvark 2010-01-19 10:16:12
找到一些其他职位:
if ((rfd = open(PIPENAME, O_RDWR | O_NONBLOCK)) < 0)
即开RDWR而不是RDONLY似乎工作...
只是这个选项没有遵守“数据包”边界(我不知道RDONLY是否会这样做,也就是说,一次可以读取多个写入 - 例如,如果读取大小大约是写入数据包的1.5倍大小... – user2220505 2015-02-05 12:08:29
关闭并重新打开该管道是正确的,唯一的解决办法,如果你想继续使用命名管道。这听起来像UNIX域套接字可能实际上更适合您的应用程序,但(它们也被文件系统中的路径名称引用,但使用BSD套接字API)。 – caf 2010-01-19 10:54:37
我尝试过使用unix套接字,但不能简单地使用“cat filename> named_pipe”。您必须编写一个专用应用程序以“套接字”方式格式化输入到您的应用程序 – ScaryAardvark 2010-01-19 14:40:33