Thread: 2 way pipes

  1. #1
    Registered User ssharish2005's Avatar
    Join Date
    Sep 2005
    Location
    Cambridge, UK
    Posts
    1,732

    2 way pipes

    Hi All,

    I have a question regarding the 2 ways pipes, which I'm having bit of trouble to get this working. I'm building test system framework for pre-build system. So I dont have the code to wrap up the system under test with my test framework. So I will have to use the binary. The system under test sometime required data from the user. But while testing it I need to send that data through the parent process. For example

    Code:
    //CHILD Process
    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
        char buf[20];
        printf("This is a test");
        fgets(buf,20,stdin);
        printf("This is second string");
        sleep(2);
        printf("This is thrid string");
        
        return 0;
    }
    Code:
    // TEST FRAMEWRK
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <unistd.h>
    int main()
    {
        int readpipe[2];
        int writepipe[2];
        char buf[100];
        int num;
        
        #define CHILD_WRITE     readpipe[1]
        #define CHILD_READ      writepipe[0]
        #define PARENT_READ     readpipe[0]
        #define PARENT_WRITE    writepipe[1]
        
        pipe(readpipe);
        pipe(writepipe);
        
        if( !fork() )
        {
            //close(0);
            close(1);
            dup( CHILD_WRITE );
            dup( CHILD_READ );
            close( PARENT_READ );
            close( PARENT_WRITE ); 
            execl("./child","./child","","","",NULL);
            _exit(0);
        }
        else
        {
            printf("PARENT: reading from pipe\n");
            close(0);
            close(1);
            dup( PARENT_READ );
            dup( PARENT_WRITE );
            close( CHILD_WRITE );
            close( CHILD_READ );
            
            while( (num = read( PARENT_READ, buf, sizeof buf ) ) )
            // while( fgets(  buf, sizeof buf, (FILE *)pfds1[0] ) )
            {
                   buf[num] = '\0';
                   open( 1 );
                   fprintf( stdout, "PARENT: read \"%s\"\n", buf);
                   close(1);
            }
            write(PARENT_WRITE,"sad\n\r",5);
            while( (num = read( PARENT_WRITE, buf, sizeof buf ) ) )
            // while( fgets(  buf, sizeof buf, (FILE *)pfds1[0] ) )
            {
                   buf[num] = '\0';
                   open( 1 );
                   fprintf( stdout, "PARENT: read \"%s\"\n", buf);
                   close(1);
            } 
        }
        return 0;
    }
    As you could see I trying to spawn child process and execv the child binary. And at some point the child requires user data which I'm trying to send through parent process. I haven't used pipes in ages and I'm missing something really fundamental. Could anyone point me out please?

    Thanks

    Harish
    Life is like riding a bicycle. To keep your balance you must keep moving - Einstein

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    You forgot to include the headers sys/stat.h and fcntl.h, required for open(). Once you've got those, you'll get diagnostics on your open(1) calls, which are incorrect (the calls, not the diagnostics). I assume you're trying to reopen standard output to the terminal(?) but you have to do more work than this (dup() the original standard output beforehand, or open /dev/tty as fd 1). I'm not sure why you're dup()ing stdin/out in the parent, though; you are just reading from/writing to the pipes, so there's no need to take over stdin/out.

    Your commented out calls to fgets() won't work, either: you can't simply treat a file descriptor as a FILE*. You could use fdopen(), though.

  3. #3
    Registered User ssharish2005's Avatar
    Join Date
    Sep 2005
    Location
    Cambridge, UK
    Posts
    1,732
    Thanks Cas for the comments. Yes your right i missed out those header files and also realised that open and close of stdin/out indeed is not needed. So took that out.

    But i'm still not able achive what i want. When the child reached the statment fgets waiting there expecting for user input. But really the input should though CHILD_READ? Is my way writing the reading through the pipes right? Do I have to use read function to read data out of the pipe.

    Code:
    CHILD
    #include <stdio.h>
    #include <unistd.h>
    
    
    int main()
    {
        char buf[20];
        
        fgets(buf,20,stdin);
        printf("You entered %s", buf);
        printf("This is second string");
        sleep(2);
        printf("This is thrid string");
        
        return 0;
    }
    Code:
    PARENT
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main()
    {
        int readpipe[2];
        int writepipe[2];
        char buf[100];
        int num;
        
        #define CHILD_WRITE     readpipe[1]
        #define CHILD_READ      writepipe[0]
        #define PARENT_READ     readpipe[0]
        #define PARENT_WRITE    writepipe[1]
        
        pipe(readpipe);
        pipe(writepipe);
        
        if( !fork() )
        {
            close(0);
            close(1);
            dup( CHILD_WRITE );
            dup( CHILD_READ );
            execl("./child","./child","","","",NULL);
            _exit(0);
        }
        else
        {
            printf("PARENT: reading from pipe\n");
            dup( PARENT_READ );
            dup( PARENT_WRITE );
            
            write(PARENT_WRITE,"sad\n\r",10);
    
            while( (num = read( PARENT_READ, buf, sizeof buf ) ) )
            {
                   buf[num] = '\0';
                   fprintf( stdout, "PARENT: read \"%s\"\n", buf);
            } 
        }
        return 0;
    }
    Thanks

    ssharish
    Life is like riding a bicycle. To keep your balance you must keep moving - Einstein

  4. #4
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    The first problem is that you're opening CHILD_WRITE as standard input and CHILD_READ as standard output. They should be switched around (or just use dup2()).

    Next, there's no reason to call dup() in your parent. You're dealing with the pipes directly. The reason you use dup()/dup2() in the child is so that the child process can communicate via its standard input/output. Since you have direct access to the pipes in the parent, there's no need to do anything with them apart from reading and writing with read() and write().

    You'll also want to close the ends of the pipes you're not using. So in your child, close the pipes that the parent process uses and vice versa.

    Finally, you're sending the string "sad\n\r" with write(), but telling write() there are 10 bytes; there are 6 (5 if you don't plan on sending the null character).

    Fix these problems and things should work (although you really should be doing error handling).

  5. #5
    Registered User ssharish2005's Avatar
    Join Date
    Sep 2005
    Location
    Cambridge, UK
    Posts
    1,732
    >The first problem is that you're opening CHILD_WRITE as standard input and CHILD_READ as standard output
    I tried inter changing them and it worked! Thanks for that cas. As i'm just thinking was actual went wrong there. For sure the understanding of pipes is not right for me. So

    Code:
    close(0);
    close(1);
    dup( CHILD_READ );
    dup( CHILD_WRITE );
    There is relation between the close and the dup functions here. I close stdin first and hence the CHILD_READ will be overlying STDIN? Is my thinking right?

    Thanks once again!

    ssharish
    Life is like riding a bicycle. To keep your balance you must keep moving - Einstein

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Quote Originally Posted by ssharish2005 View Post
    >
    There is relation between the close and the dup functions here. I close stdin first and hence the CHILD_READ will be overlying STDIN? Is my thinking right?
    Correct. dup() will use the lowest available file descriptor. Thus when you close 0 and 1, the first dup() will use 0 (standard input) and the next will use 1 (standard input). dup2() is a combination of these two: it performs the close() itself if necessary, and moreover allows you to choose any descriptor, not just the lowest available.

  7. #7
    Registered User ssharish2005's Avatar
    Join Date
    Sep 2005
    Location
    Cambridge, UK
    Posts
    1,732
    Thanks for the clarification Cas. Really appreciate it.

    ssharish
    Life is like riding a bicycle. To keep your balance you must keep moving - Einstein

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. creating an array of pipes
    By arkashkin in forum Linux Programming
    Replies: 1
    Last Post: 08-30-2010, 09:22 AM
  2. Sending Structs pointers through pipes
    By kiros88 in forum C Programming
    Replies: 11
    Last Post: 09-02-2009, 02:59 PM
  3. threads and pipes
    By kiros88 in forum C Programming
    Replies: 3
    Last Post: 08-20-2009, 06:03 PM
  4. Pipes sometimes fail
    By EVOEx in forum Linux Programming
    Replies: 2
    Last Post: 05-02-2009, 01:47 PM
  5. Services and Pipes
    By nickname_changed in forum Windows Programming
    Replies: 0
    Last Post: 07-16-2003, 06:46 AM