Thread: IPC using PIPES

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    20

    IPC using PIPES

    parent.c
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <string.h>
    
    /*
     *Decimal number is taken in through standard input and
     *output to a file called bin.txt
     */
    int main(int argc, char* argv[]){
    	pid_t pid;
    	int rv;
    	int	commpipe[2];		/* This holds the fd for the input & output of the pipe */
    	char input[100];
    	FILE *inputfile;
    	FILE *outputfile;
    	inputfile = fopen("dec.txt", "r");
    	outputfile = fopen("bin.txt", "w");
    	
    	if(inputfile == NULL) fprintf(stderr, "dec.txt NOT opened successfully\n");
    	else fprintf(stderr, "dec.txt opened successfully\n");
    	
    	if(outputfile == NULL) fprintf(stderr, "bin.txt NOT created successfully\n");
    	else fprintf(stderr, "bin.txt created successfully\n");
    	
    	/* Setup communication pipeline first */
    	if(pipe(commpipe)){
    		fprintf(stderr,"Pipe error!\n");
    		exit(1);
    	}
    	
    	/* Attempt to fork and check for errors */
    	if( (pid=fork()) == -1){
    		fprintf(stderr,"Fork error. Exiting.\n");  /* something went wrong */
    		exit(1);        
    	}
    	
    	if(pid == 0){
    		dup2(commpipe[0], 0);
    		close(commpipe[1]);
    		if(execl("child","child",NULL) == -1){
    			fprintf(stderr,"execl Error!");
    			exit(1);
    		}
    		
    	}
    	else{
    		/* A positive (non-negative) PID indicates the parent process */
    		dup2(commpipe[1],1);	/* Replace stdout with out side of the pipe */
    		close(commpipe[0]);		/* Close unused side of pipe (in side) */
    		setvbuf(stdout,(char*)NULL,_IONBF,0);	/* Set non-buffered output on stdout */
    		while(fscanf(inputfile, "%s", &input) != EOF){
    			printf("%s\n", input);
    		}
    		close(commpipe[1]);
    		dup2(fileno(stdout), 1);
    		printf("Pipe closed\n");
    	}
    	wait(&rv);				/* Wait for child process to end */
    
    	return 0;
    	
    }
    child.c
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <string.h>
    void dectohex(int decimal, char *hex){
    	int index=0;
    	
    	while(decimal){
    		hex[index] = (decimal%16) < 10 ? (decimal%16): 'A' + (decimal%16) - 10;
    	}
    	printf("%d\n", hex);
    }
    /*
     *Will take a decimal number from the stantard input and
     *output the hexidecimal version to hex.txt
     */
    int main(int argc, char* argv[]){
    	char input[256];
    	char hex[256];	
    	do{
    		if(fgets(input, sizeof(input), stdin) != NULL)
    			printf("Child got: %s", input);
    	}while(!feof(stdin));
    	
    	return 0;
    }
    What I have here is the code from two processes.
    The child is simple:
    When it is run alone it will take input from the terminal and will re-output the input that was given separated by \n. It will stop running when EOF is encountered (user input ctrl D)

    The Parent is a bit more complex:
    The parent will get its input from a file "input.txt" "input.txt" will contain random words or numbers, one per line. The parent is forked, a child is created (child.c) which is then duped into taking its input from a pipe called commpipe.
    The parent will feed the child input and the child will output what it was fed.

    All of this is done well enough but what I need is a way for the child to be handed an EOF when the EOF of input.txt is encounter. What can I change in parent.c or child.c to get this.
    Is there a way to just close the writing end of the pipe and have the child detect that the parent's writing end of the pipe is no longer open?

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by BMathis View Post
    Is there a way to just close the writing end of the pipe and have the child detect that the parent's writing end of the pipe is no longer open?
    Have you tried that (just closing the end of the pipe)?

    Another possibility is to just communicate with the child (send "END" or something, and then close it, and the child closes when it recieves "END").
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Feb 2009
    Posts
    20
    Quote Originally Posted by MK27 View Post
    Another possibility is to just communicate with the child (send "END" or something, and then close it, and the child closes when it recieves "END").
    I do not want to send the child flags by having to type "END" or something similar at the end of every file. That does not achieve what I am trying to get.


    Quote Originally Posted by MK27 View Post
    Have you tried that (just closing the end of the pipe)?
    Am I not doing that with the
    Code:
    close(commpipe[1]);
    If so, then I need to know a way to make the child process check if the writing end of the pipe has been closed.

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by BMathis View Post
    I do not want to send the child flags by having to type "END" or something similar at the end of every file. That does not achieve what I am trying to get.
    Nor am I and neither would anybody else.

    If the child is reading the file directly, it will encounter an EOF, so this is a moot point. If it is not (ie, if it is reading from a pipe), you transmit from the other end:
    Code:
    if/when/whatever {
             fwrite ("END\n\0", 5, 1, pipe)
    }
    If you do not want to use a word because this could conflict with the content (ie, there could be an "END" you didn't intend, use a non-alphabetic byte:
    Code:
    #define END 0x06
    
    char byte;
    while ((fread(&byte,1,1,pipe))==1) {
           if (byte==END) close(pipe);
           otherwise do stuff
    }
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Registered User
    Join Date
    Feb 2009
    Posts
    20
    This cant work because the child would end upon encountering something other than ctrl D.

    If the child is run by itself then the user should be able to type words indefinitely until he or she hits ctrl D. Then the child will stop reading.

    I could have easily made the loop break upon seeing an END or some other reserved word but that does not achieve what I am trying to do here.

    I want they parent (in a manner of speaking) to either send a EOF, ctrl D, w/e through the pipe to the child or I want the parent to close its side of the pipe and have the child detect that the parent has closed its end of the pipe.

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by BMathis View Post
    I want they parent (in a manner of speaking) to either send a EOF, ctrl D, w/e through the pipe to the child
    Then do that (send an EOF or a ctrl-d to the child). The idea is exactly the same, just my idea is slightly more foolproof and requires a wooping 2 more lines of code (at most). If you don't want to read byte by byte (personal preference, but that's up to you), just use strchr on the input. Look:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    #define END 0x06
    
    int main() {
    	char string[32]="your message here";
    	int len=strlen(string);
    	if (strchr(string,END)) puts("won't happen");
    	string[len]=END; string[len+1]='\0'; /* null terminate */
    	if (strchr(string,END)) puts("done");
    	return 0;
    }
    You can actually replace END with EOF in that code, b/t/w, which means you don't need any #define (EOF is already defined, on my system it appears to be 0xffffffff, but that doesn't matter).
    Last edited by MK27; 03-14-2009 at 02:00 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    Feb 2009
    Posts
    20
    Quote Originally Posted by MK27 View Post
    Then do that (send an EOF or a ctrl-d to the child). The idea is exactly the same, just my idea is slightly more foolproof and requires a wooping 2 more lines of code (at most).
    I know this is stupid but HOW do i send the EOF? Can i send it through the stdout using printf() and if so, how?

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Sorry, I just took some time to do an edit that probably should have been a fresh post, so read that last one again. Really.

    ps. using printf:
    Code:
    printf("your message here%c",EOF);
    Last edited by MK27; 03-14-2009 at 02:03 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    Registered User
    Join Date
    Feb 2009
    Posts
    20
    Like, I literally want to send ctrl D through the pipe to the child.

  10. #10
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by BMathis View Post
    Like, I literally want to send ctrl D through the pipe to the child.
    Just use EOF! Use ctrl-d to trigger it.
    Code:
    printf("your message here%c",EOF);
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  11. #11
    Registered User
    Join Date
    Feb 2009
    Posts
    20
    That seems as though it would work but my child program just spits out "Child got:?" and sits there waiting for more stuff to read through the pipe.

    For some reason it is seeing that EOF as something that can only be represented as ?

  12. #12
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by BMathis View Post
    That seems as though it would work but my child program just spits out "Child got:?" and sits there waiting for more stuff to read through the pipe.

    For some reason it is seeing that EOF as something that can only be represented as ?
    I don't use fgets much, but I think you have two choices:
    1) use fread, which recognizes EOF, but doesn't stop on newlines (meaning you might have to find a way to deal with that), or
    2) use fgets, which does not recognize EOF but will stop on a newline. In that case, you will have to inspect the input (using strchr or whatever) for an EOF.

    The reason you see a "?" is because 0xffffffff is not a printable character.

    I think this line is not so great:
    Code:
    	}while(!feof(stdin));
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by MK27
    use fgets, which does not recognize EOF but will stop on a newline. In that case, you will have to inspect the input (using strchr or whatever) for an EOF.
    Once EOF is reached, fgets() stops reading. Remember, EOF is not a character, but a macro of some negative integer used for an error condition code.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    Registered User
    Join Date
    Feb 2009
    Posts
    20
    Code:
    while(fgets(input, sizeof(input), stdin)!=NULL){
    		if(strchr(input, EOF)) break;
    		else printf("Child got: %s", input);
    	}
    seems to work so far

  15. #15
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by BMathis View Post
    I know this is stupid but HOW do i send the EOF? Can i send it through the stdout using printf() and if so, how?
    You don't "send" EOF. You just close your end of the pipe, and the OS itself will generate EOF. The situation is different if the reading end of the pipe gets closed -- that doesn't generate EOF to the writer, instead it causes a SIGPIPE to be delivered, which by default will crash your program. You should design a real protocol with true shutdown negotiation to avoid this problem.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Pipes sometimes fail
    By EVOEx in forum Linux Programming
    Replies: 2
    Last Post: 05-02-2009, 01:47 PM
  2. Pipes
    By Martin Kovac in forum C Programming
    Replies: 1
    Last Post: 03-31-2009, 03:09 AM
  3. Simulating wireless netowork using IPC
    By tenkasian in forum C Programming
    Replies: 3
    Last Post: 03-23-2009, 04:16 PM
  4. Segmentation fault - IPC
    By kbfirebreather in forum C Programming
    Replies: 7
    Last Post: 02-01-2009, 03:17 PM
  5. Services and Pipes
    By nickname_changed in forum Windows Programming
    Replies: 0
    Last Post: 07-16-2003, 06:46 AM