Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++, Linux] Jak przechwycić stdin, stdout i stderr dla programu uruchamianego z poziomu kodu

Ostatnio zmodyfikowano 2015-01-13 17:32
Autor Wiadomość
DejaVu
Temat założony przez niniejszego użytkownika
[C++, Linux] Jak przechwycić stdin, stdout i stderr dla programu uruchamianego z poziomu kodu
» 2015-01-13 15:15:38
C/C++
#include <unistd.h>
#include <stdio.h>
#include <cstdlib>

/* since pipes are unidirectional, we need two pipes.
   one for data to flow from parent's stdout to child's
   stdin and the other for child's stdout to flow to
   parent's stdin */

#define NUM_PIPES          2

#define PARENT_WRITE_PIPE  0
#define PARENT_READ_PIPE   1

int pipes[ NUM_PIPES ][ 2 ];

/* always in a pipe[], pipe[0] is for read and
   pipe[1] is for write */
#define READ_FD  0
#define WRITE_FD 1

#define PARENT_READ_FD  ( pipes[PARENT_READ_PIPE][READ_FD]   )
#define PARENT_WRITE_FD ( pipes[PARENT_WRITE_PIPE][WRITE_FD] )

#define CHILD_READ_FD   ( pipes[PARENT_WRITE_PIPE][READ_FD]  )
#define CHILD_WRITE_FD  ( pipes[PARENT_READ_PIPE][WRITE_FD]  )

int main()
{
    int outfd[ 2 ];
    int infd[ 2 ];
   
    // pipes for parent to write and read
    pipe( pipes[ PARENT_READ_PIPE ] );
    pipe( pipes[ PARENT_WRITE_PIPE ] );
   
    if( !fork() ) {
        char * argv[] = { "/usr/bin/bc", "-q", 0 };
       
        dup2( CHILD_READ_FD, STDIN_FILENO );
        dup2( CHILD_WRITE_FD, STDOUT_FILENO );
       
        /* Close fds not required by child. Also, we don't
                   want the exec'ed program to know these existed */
        close( CHILD_READ_FD );
        close( CHILD_WRITE_FD );
        close( PARENT_READ_FD );
        close( PARENT_WRITE_FD );
       
        execv( argv[ 0 ], argv );
    } else {
        char buffer[ 100 ];
        int count;
       
        /* close fds not required by parent */
        close( CHILD_READ_FD );
        close( CHILD_WRITE_FD );
       
        // Write to child’s stdin
        write( PARENT_WRITE_FD, "2^32\n", 5 );
       
        // Read from child’s stdout
        count = read( PARENT_READ_FD, buffer, sizeof( buffer ) - 1 );
        if( count >= 0 ) {
            buffer[ count ] = 0;
            printf( "%s", buffer );
        } else {
            printf( "IO Error\n" );
        }
    }
}
Źródło: https://jineshkj.wordpress.com​/2006/12/22​/how-to-capture-stdin-stdout-an​d-stderr-of-child-program​/

Dodatkowe informacje: http://stackoverflow.com​/questions/280571​/how-to-control-popen-stdin-stdout-stderr-redirection
P-124798
akwes
» 2015-01-13 16:29:40
Może alternatywnie:
glib (cross-platform):
g_spawn_async_with_pipes
g_spawn_sync

P-124800
DejaVu
Temat założony przez niniejszego użytkownika
» 2015-01-13 17:32:21
C/C++
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <cmath>
#include <sys/select.h>
#include <termios.h>
#include <stropts.h>
#include <sys/ioctl.h>

int _kbhit() {
    static const int STDIN = 0;
    static bool initialized = false;
   
    if( !initialized ) {
        // Use termios to turn off line buffering
        termios term;
        tcgetattr( STDIN, & term );
        term.c_lflag &= ~ICANON;
        tcsetattr( STDIN, TCSANOW, & term );
        setbuf( stdin, NULL );
        initialized = true;
    }
   
    int bytesWaiting;
    ioctl( STDIN, FIONREAD, & bytesWaiting );
    return bytesWaiting;
}

class CaptureIO
{
private:
    typedef int PipeReadWrite[ 2 ];
    PipeReadWrite m_pipeRead;
    PipeReadWrite m_pipeWrite;
   
    static int getDescriptorState( int filedes, float _seconds )
    {
        // Initialize the file descriptor set:
        fd_set waitingList;
        FD_ZERO( & waitingList );
        FD_SET( filedes, & waitingList );
       
        // Initialize the timeout data structure:
        timeval timeout;
        float reszta = fmod( _seconds, 1.0f );
        timeout.tv_sec = static_cast < int >( _seconds );
        timeout.tv_usec = static_cast < int >( reszta * 1000000 );
       
        // select returns 0 if timeout, 1 if input available, -1 if error.
        return select( FD_SETSIZE, & waitingList, NULL, NULL, & timeout );
    }
   
public:
    int getChildReadDescriptor() const { return m_pipeWrite[ 0 ]; }
    int getChildWriteDescriptor() const { return m_pipeRead[ 1 ]; }
   
    int getParentReadDescriptor() const { return m_pipeRead[ 0 ]; }
    int getParentWriteDescriptor() const { return m_pipeWrite[ 1 ]; }
   
    void initPipes()
    {
        ::pipe( m_pipeRead );
        ::pipe( m_pipeWrite );
    }
   
    void runApplicationAtChild( const char * _sApplication )
    {
        ::dup2( getChildReadDescriptor(), STDIN_FILENO );
        ::dup2( getChildWriteDescriptor(), STDOUT_FILENO );
       
        // Zamykamy wszystkie deskryptory ponieważ nie są one potrzebne dla aplikacji, która będzie uruchomiona.
        ::close( getChildReadDescriptor() );
        ::close( getChildWriteDescriptor() );
        ::close( getParentWriteDescriptor() );
        ::close( getParentWriteDescriptor() );
       
        //execv(argv[0], argv);
        ::system( _sApplication );
    }
   
    void initCommunication()
    {
        //Zamykamy deskryptory, które nie są potrzebne na parencie.
        ::close( getChildReadDescriptor() );
        ::close( getChildWriteDescriptor() );
    }
   
    void write( char _c )
    {
        write( & _c, 1 );
    }
   
    void write( const char * _sText )
    {
        write( _sText, strlen( _sText ) );
    }
   
    void write( const char * _sText, size_t _length )
    {
        ::write( getParentWriteDescriptor(), _sText, _length );
    }
   
    bool isReadingFailed() const
    {
        return getDescriptorState( getParentReadDescriptor(), 0.05f ) ==- 1;
    }
   
    bool isWaitingForReading() const
    {
        return getDescriptorState( getParentReadDescriptor(), 0.05f ) == 1;
    }
   
    bool read( char * _buffer, size_t _sizeInBytes )
    {
        _buffer[ 0 ] = 0;
       
        if( !isWaitingForReading() )
             return true;
       
        if( _sizeInBytes == 0 )
             return true;
       
        int count =::read( getParentReadDescriptor(), _buffer, _sizeInBytes - 1 );
        if( count > 0 ) {
            _buffer[ count ] = 0;
            return true;
        } else {
            return false;
        }
    }
};

int main()
{
    CaptureIO app;
    app.initPipes();
    if( fork() )
    {
        app.initCommunication();
        bool bContinue = true;
        while( bContinue )
        {
            char buffer[ 100 ];
            while( bContinue && app.isWaitingForReading() )
            {
                bContinue = app.read( buffer, sizeof( buffer ) );
                printf( "%s", buffer );
                fflush( stdout );
            }
            if( !app.isWaitingForReading() && _kbhit() > 0 )
            {
                int c = getc( stdin );
                app.write( static_cast < char >( c ) );
            } //if
        } //while
        printf( "Closing main application.\n" );
    } else
    {
        app.runApplicationAtChild( "/usr/bin/bc -q" );
        printf( "Application closed!\n" );
    } //else
    return 0;
}
P-124806
« 1 »
  Strona 1 z 1