Thread: bidirectional pipes

  1. #1
    Registered User
    Join Date
    May 2011
    Posts
    116

    bidirectional pipes

    hi all!

    I'm writing a C++ program where I have a parent and a child process which communicate with a bidirectional pipe.The parent process creates the pipe and WRITES a string to it.Then the child process READS the string the parent sent and WRITES data to the pipe,which after the parent READS.
    It's the first time I have to deal with a bidirectional pipe and I'm not sure how to do it.
    Here's what I have tried so far

    Code:
    //parent
    
    int r = mkfifo (pipeName, 0666);
    if (r < 0) {
      perror("Error creating in creation");
      exit (1);
    }
    
    //parent opens pipe for reading and writing
    int fd = open(pipeName,O RDWR);
    
    dup2(1,fd);
    
    //everything parent writes go to fd
    
    int pid=fork();
    
    if(pid==0){
       //child process
       //exec child and send to it the name of the pipe
    }
    I'm sure is wrong but I have only used one-way pipes so far so it's difficult to understand how bidirectional pipes do work..
    Any help would be very appreciated!
    Thank you

  2. #2
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    you can avoid creating a fifo by using the pipe() system call. you pass it an array of two integers, and it fills the array with two file descriptors. do it twice to create pipes for both stdin and stdout. fork() and dup(), and then voila, you'll have a bidirectional pipe.

  3. #3
    Registered User
    Join Date
    May 2011
    Posts
    116
    Quote Originally Posted by Elkvis View Post
    you can avoid creating a fifo by using the pipe() system call. you pass it an array of two integers, and it fills the array with two file descriptors. do it twice to create pipes for both stdin and stdout. fork() and dup(), and then voila, you'll have a bidirectional pipe.
    Do you mean something like this?

    Code:
    main(){
      
      int     fd[2];
      pipe(fd);
    
      childpid = fork();
            
      if(childpid == 0)
       {
            //child reads from fd[0] instead of stdin
            dup2(0, fd[0]);
            //exec child  
          }
       else{
           //parent writes to fd[1] instead of stdout
           dup2(1, fd[1]);
    
       }
    }
    It's really confusing.Could you please give me an example?
    Thank you

  4. #4
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    you probably don't need to call dup2() in the parent process, because it would then take the place of your existing stdout, unless that's exactly what you're going for. otherwise, what you've got there is pretty much right on. if you want to hook up both stdin and stdout, you'll need to call pipe() with another pair of ints, and hook them up exactly the opposite of the others. make sure to close the unused end of the pipe in each process - close(fd[1]) in the child, and close(fd[0]) in the parent.

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Pipes don't work that way. If both processes want to read AND write, you need two pipes, one for the parent sending data to the child, one for the child sending data to the parent. Or use a socket instead of a pipe.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    like I said in my first reply...

  7. #7
    Registered User
    Join Date
    May 2011
    Posts
    116
    Quote Originally Posted by Elkvis View Post
    you probably don't need to call dup2() in the parent process, because it would then take the place of your existing stdout, unless that's exactly what you're going for. otherwise, what you've got there is pretty much right on. if you want to hook up both stdin and stdout, you'll need to call pipe() with another pair of ints, and hook them up exactly the opposite of the others. make sure to close the unused end of the pipe in each process - close(fd[1]) in the child, and close(fd[0]) in the parent.

    Does this seem ok?

    Code:
    main(){
       
      int     fd[2];
      int     fds[2];
      pipe(fd);
      pipe(fds);
     
      childpid = fork();
             
      if(childpid == 0)
       {
            //child reads from fd[0] instead of stdin
            dup2(0, fd[0]);
            dup2(1,fds[1]);
    
            close(fd[1]);
            close(fds[0]); 
            
             //exec child  
    
          }
       else{
           //parent writes to fd[1] instead of stdout
           dup2(1, fd[1]);
           dup2(0,fds[0]);
    
          close(fd[0]);
           close(fds[1]); 
       }
    }
    Also since I replace stdin and stdout I dont have to send the file descriptor while exec-ing the child.On the other hand if I didn't replace the stdin and stdout I should send the file descriptor.Right?

  8. #8
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    that looks ok. if you didn't replace stdin and stdout, you'd have to find a way to notify the child process that it should use some other file descriptor for each. using dup2 is just simpler. if you still want your parent process to have its own stdin/stdout, you could use something like fdopen() to create buffered C-style streams from those file descriptors. the boost libraries also have adapter classes to make istream/ostream objects from the descriptors, but that may be a discussion for another thread.

  9. #9
    Registered User
    Join Date
    May 2011
    Posts
    116
    Quote Originally Posted by Elkvis View Post
    that looks ok. if you didn't replace stdin and stdout, you'd have to find a way to notify the child process that it should use some other file descriptor for each. using dup2 is just simpler. if you still want your parent process to have its own stdin/stdout, you could use something like fdopen() to create buffered C-style streams from those file descriptors. the boost libraries also have adapter classes to make istream/ostream objects from the descriptors, but that may be a discussion for another thread.
    I changed it a bit into this:

    Code:
    int  fd[2];
    int  fds[2];
    pipe(fd);
    pipe(fds);
    
    int childpid = fork();
    	
    	if(childpid == 0)
    	{
    	close(fd[1]);
    	close(fds[0]); 
    	
    	fd[0] = open("test1",O_RDONLY);
    	fds[1] = open("test2",O_WRONLY)
    
    dup2(fd[0],0);
    	dup2(fds[1],1);//child writes to fds[1]
    
    char wrd[128];
    
    cin.getline(wrd,'\0');
    		cout<<wrd<<endl;
    
    close(fd[0]);
    	close(fds[1]);
    	//exec child  
    
    }
    	else{
    	close(fd[0]);
    	close(fds[1]); 
    	
    	fd[1] = open("test1",O_WRONLY);
    	fds[0] = open("test2",O_RDONLY);
    	//parent writes to fd[1] instead of stdout
    	dup2(fd[1],1);
    	dup2(fds[0],0);
    
    	cout<<"aaaa.dddd.ffff.gggg"<<endl;
    	
    	close(fd[1]);
    	close(fds[0]);
    	}
    The problem is that although parent writes to test1 and the child tries to read from it(child's cout to test1 works,I've checked it)sometimes it reads the half line and sometimes nothing at all as child's cout is in test2 and only sometimes there's something written there and yet not the whole thing.What could be wrong?

  10. #10
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    One definite problem is your call to getline. The second parameter should be 128 (max chars to read).

    I have no idea what the open calls are for. Try commenting all of them out.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  11. #11
    Registered User
    Join Date
    May 2011
    Posts
    116
    Quote Originally Posted by oogabooga View Post
    One definite problem is your call to getline. The second parameter should be 128 (max chars to read).

    I have no idea what the open calls are for. Try commenting all of them out.
    Actually I changed it to reading one character at a time instead of the whole line.
    Don't I need the open calls in order to specify the files the proccesses read from and write to?

  12. #12
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    I don't understand. Do you want pipes or files? If pipes, then don't open the files.

    As it stands, if test1 and test2 don't exist, then your open calls will return -1. If they do exist, then you have uncoordinated access to them and the pipes you set up are not being used.

    Again, try commenting them out.
    Last edited by oogabooga; 06-05-2012 at 01:07 PM.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  13. #13
    Registered User
    Join Date
    May 2011
    Posts
    116
    Quote Originally Posted by oogabooga View Post
    I don't understand. Do you want pipes or files? If pipes, then don't open the files.

    As it stands, if test1 and test2 don't exist, then your open calls will return -1. If they do exist, then you have uncoordinated access to them and the pipes you set up are not being used.

    Again, try commenting them out.
    OK i did what you told me .If cout works for writing to the pipe,how do I read from it,let's say the first line?

    what I did above doesn't work..

  14. #14
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    since you're redirecting stdin and stdout in both the parent and the child, try something like this:
    Code:
    std::string s;
    std::getline(std::cin, s, '\0'); //could just say 0 but '\0' makes it clear that it's a char value

  15. #15
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Since you've re-assigned stdin and stdout in both the parent and child to the pipes, I'm not sure how you expect to see any output!

    What exactly do you wish to achieve with your bidirectional pipe? I.e., post the current version of your program and state what you think the output should be and what it actually is.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bidirectional loop? (Increase/decrease depending on values)
    By BlueGooGames in forum C Programming
    Replies: 4
    Last Post: 01-08-2011, 12:08 PM
  2. 2 way pipes
    By ssharish2005 in forum C Programming
    Replies: 6
    Last Post: 10-25-2010, 04:21 AM
  3. pipes in c
    By ajal1 in forum C Programming
    Replies: 6
    Last Post: 10-29-2005, 03:29 PM
  4. pipes
    By moi in forum C Programming
    Replies: 8
    Last Post: 08-11-2004, 01:59 PM
  5. Need some help with pipes please.
    By carrja99 in forum C Programming
    Replies: 1
    Last Post: 05-05-2004, 04:13 PM