3

我遇到了一个问题,我必须从命名管道中读取。我必须处理命名管道的编写者来来去去的情况,但我需要在整个应用程序中保持相同的管道打开。

我在下面的代码中总结了这一点。

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 状态,以便 select 现在会阻塞。但是,我不知道该怎么做。

我投身于你的集体智慧:) 马克。

4

3 回答 3

4

好的,我想出了一个解决方案,但我对此并不满意。如果你问我,这有点像“敲碎坚果的锤子”。

.....
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
.....

基本上,我关闭并重新打开管道。

我仍然欢迎更好的解决方案。

于 2010-01-19T09:33:04.523 回答
1

在其他帖子上找到:

if ( (rfd = open( PIPENAME, O_RDWR | O_NONBLOCK )) < 0 )

即打开 RDWR 而不是 RDONLY 似乎工作......

于 2015-02-05T09:02:32.417 回答
-1

您是否尝试过以非阻塞模式打开 fds,当您read()返回EWOULDBLOCK/时EAGAINclearerr()在 fd 上执行操作?

于 2010-01-19T09:41:02.680 回答