multiple messages through a pipe - c

I am trying to send two messages "hello World" and "Goodbye" from parent to a child using a pipe. The child must print the messages when recieves them.
My problem is how to send the second message. I compile and run the program but it only prints the first message. Any sugestions?
Here's my code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 50
void main(){
int fd[2], n, status;
char buf[MAX];
pid_t pid;
char str1[]="Hello World!\n";
char str2[]="Goodbye\n";
pipe(fd);
if((pid=fork())<0){
abort();
}
else if(pid>0){// parent code goes here
close (fd[0]); // close read channel of parent
/*Send "hello world" through the pipe*/
write(fd[1],str1,(strlen(str1))); // write to the pipe
wait(&status);
close(fd[0]);
write(fd[1],str2,(strlen(str2)));
}
else{ // child code goes here
close(fd[1]); // close write channel of child
n=read(fd[0], buf, sizeof(buf)); // reads from the pipe
write(STDOUT_FILENO, buf, n);
exit(0);
}
}

In the parent, just write the two messages and then close the write end of the pipe:
close(fd[0]); // close read channel of pipe in parent
write (fd[1], str1, strlen(str1)); // write "hello world"
write (fd[1], str2, strlen(str2)); // write "goodbye"
close(fd[1]); // Tell child that we're done writing
wait(&status); // Wait for child to read everything and exit
In the child, you should read in a loop until you get EOF, indicated by read() returning 0:
close(fd[1]); // close write channel of pipe in child
while ((n = read(fd[0], buf, sizeof(buf)) > 0) { // Read until it returns 0 (EOF) or -1 (error)
write(STDOUT_FILENO, buf, n);
}
if (n < 0) { // -1 = error
perror("read from pipe");
}

Related

modify text in child process to use in parent

I am trying to create a simple pipe/fork function, so that child process modifies the value of text, then it is printed by the parent.
I have checked a similar question on Modify variable in child process, but I am unable to print the text variable in the parent.
int main()
{
pid_t childp;
char text[100];
pipe(text);
childp = fork();
if (childp ==0){
strncpy(text, "Hello world", 100); // child running
}
else{
printf("%s\n", text); // parent prints "Hello world"
}
return 1;
}
Any help is appreciated (I am very new to C language)
look into this website :
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string)+1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
}
return(0);
}
It explain how to properly use C pipes. Take a look to this too.
Add this for error handling :
if (pipe(fd) == -1) {
fprintf(stderr, "Pipe Failed");
return 1;
}
The closest to your code working example I can come up with.
int main()
{
pid_t childp;
char text[100];
int fd[2];
pipe(fd);
childp = fork();
if (childp ==0){
FILE *f=fdopen(fd[1], "w"); // Write into this "file" what you want the other end to read.
fprintf(f, "Hello world\n");
}
else{
FILE *f=fdopen(fd[0], "r"); // We can read from this "file"
fgets(text, 100, f); // Read one line of text from the "file" up to 100 bytes
printf("read <%s> from by new child\n", text)
}
return 1;
}
Note again that this is not a shared buffer. So you need both end to agree on a "protocol". Because everything that is written by one end must be read by the other (otherwise the "write" instruction will be blocked), and everything that is read by one end, must be writter by the other (otherwise the "read" instruction will be blocked).
So, either you use a fixed size message, for example. If you choose 100, you need to write 100 bytes exactly at one end (fill with 0 if needed), and read 100 bytes exactly at the other.
Or you find some protocol so that the reading end knows exactly when to stop reading.
I choose the latter (because it is the closest to your code). By using fgets to read, that stop to read at each newline, and fprintf a message ended by a newline at the writing end.

read() System call and Null-terminated string

If I have the following array :
char message_buffer [100] ="Hello World ";
If I then use an ordinary pipe to send this buffer from the parent process to a child and then at the child , I have used the following code :
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main()
{
char message_buffer[100] = "Hello World ";
char read_buffer[100];
int return_value;
int fd[2];
return_value = pipe(fd);
if (return_value < 0)
{
printf("Error creating the pipe");
exit(1);
}
int rc = fork();
if (rc < 0)
{
printf("Error forking a child");
exit(1);
}
if (rc > 0)
{
printf("I am the parent , I will write the message now into the pipe. \n");
close(fd[0]);
write(fd[1], message_buffer, 100);
close(fd[1]);
wait(NULL);
}
else
{
printf("I am the child , I will read the message from the pipe. \n");
close(fd[1]);
read(fd[0], read_buffer, 100);
close(fd[0]);
printf("Message recieved: %s", read_buffer);
}
In this situation, the print statement will work without printing any garbage value. However, assume we have a file copying program that copies the content of a file to another file, where the source file will have the content "hello world" and then we read this message into a buffer and send it through a pipe to a child:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
void main()
{
char buffer[100];
char childbuff[100];
int fd[2], des, bytes, target;
pipe(fd);
if (fork())
{
/* parent process closes the downstream */
close(fd[0]);
/* reads the file */
des = open("test.txt", O_RDONLY);
bytes = read(des, buffer, sizeof(buffer));
/* puts data in pipe */
write(fd[1], buffer, bytes);
}
else
{
/* Child process closes the upstream */
close(fd[1]);
/* reads from the pipe */
read(fd[0], childbuff, sizeof(childbuff));
close(fd[0]);
/* output the received string */
printf("\nReceived string is -- %s", childbuff);
target = open("copy.txt", O_CREAT, 00777);
write(target, childbuff, (strlen(childbuff) - 1));
}
}
In this case, I get a garbage value along the message received when I run the print statement. I know that the read() doesn't Null terminate the buffer. But my question is why the print statement has worked fine in the first case (in which we have only transferred an array), while it didn't work fine in the second case (in which we have transferred a content of a file)?

Using pipes to communicate between a parent and a child

In an attempt to better understand how pipes work in C, I decided to create a simple program. It is supposed to do the following: Firstly, I fork the program. The parent then reads from the standard input and writes everything into a pipe until EOF is reached. The child then reads from that pipe and writes the content back into another pipe, which is then supposed to be read by the parent process and written into the standard output.
Yes, the program isn't very "useful", but I'm just trying to familiarize myself with pipes and how to use them. This is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
char buf;
int pipe_one[2];
int pipe_two[2];
pid_t child;
if(pipe(pipe_one) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
if(pipe(pipe_two) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
child = fork();
switch (child) {
case -1:
fprintf(stderr, "Error while forking.\n");
break;
case 0:
// child
// close unnecessary ends
close(pipe_one[1]);
close(pipe_two[0]);
// read input from parent and write it into pipe
while(read(pipe_one[0], &buf, 1) > 0) {
write(pipe_two[1], &buf, 1);
}
write(pipe_two[1], "\n", 1);
close(pipe_one[0]);
close(pipe_two[1]);
break;
default:
// parent
// close unnecessary ends
close(pipe_one[0]);
close(pipe_two[1]);
// read from standard input and write it into pipe
while(read(STDIN_FILENO, &buf, 1) > 0) {
write(pipe_one[1], &buf, 1);
}
write(pipe_one[1], "\n", 1);
close(pipe_one[1]);
// wait for child process to finish
wait(NULL);
// read from pipe that child wrote into
while(read(pipe_two[0], &buf, 1) > 0) {
write(STDOUT_FILENO, &buf, 1);
}
write(STDOUT_FILENO, "\n", 1);
close(pipe_two[0]);
break;
}
exit(EXIT_SUCCESS);
}
Expected behavior: In the beginning, the program reads user input until EOF is reached and then it outputs everything again into the standard output.
Actual behavior: The program reads the whole input, but once EOF is reached it just terminates (succesfully) without writing anything into the standard output. What am I doing wrong? I'd be happy if someone could look over it and help me out.
You close pipes for your parent in your child.
while(read(pipe_one[0], &buf, 1) > 0) {
write(pipe_two[1], &buf, 1);
}
write(pipe_two[1], "\n", 1);
close(pipe_one[0]); // Here you close pipes
close(pipe_two[1]); // for your parent
So the parent can't receive anything. Just remove those two lines and it will work.

C Pipe to STDIN of Another Program

I can barely understand the man page for pipe, so I kinda need help understanding how to take a piped input in an external executable.
I have 2 programs: main.o & log.o
I written main.o to fork. Here is what it is doing:
Parent fork will pipe data to the child
Child fork will exec log.o
I need the child fork for main to pipe to STDIN of log.o
log.o simply takes STDIN & logs with time stamp to a file.
My code is composed of some code from various StackOverflow pages I dont remember & the man page for pipe:
printf("\n> ");
while(fgets(input, MAXINPUTLINE, stdin)){
char buf;
int fd[2], num, status;
if(pipe(fd)){
perror("Pipe broke, dood");
return 111;
}
switch(fork()){
case -1:
perror("Fork is sad fais");
return 111;
case 0: // Child
close(fd[1]); // Close unused write end
while (read(fd[0], &buf, 1) > 0) write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(fd[0]);
execlp("./log", "log", "log.txt", 0); // This is where I am confused
_exit(EXIT_FAILURE);
default: // Parent
data=stuff_happens_here();
close(fd[0]); // Close unused read end
write(fd[1], data, strlen(data));
close(fd[1]); // Reader will see EOF
wait(NULL); // Wait for child
}
printf("\n> ");
}
I suppose this is what you're going to do:
1. main fork, parent pass message to child via pipe.
2. child receive message from pipe, redirect message to STDIN, execute log.
3. log receive message from STDIN, do something.
the key to do this is dup2 to redirect file descriptor, from pipe to STDIN.
This is the modified simple version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int fd[2];
char buf[] = "HELLO WORLD!";
if(pipe(fd)){
perror("pipe");
return -1;
}
switch(fork()){
case -1:
perror("fork");
return -1;
case 0:
// child
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execl("./log", NULL);
default:
// parent
close(fd[0]);
write(fd[1], buf, sizeof(buf));
close(fd[1]);
wait(NULL);
}
printf("END~\n");
return 0;
}
I can suggest a simpler approach. There's a function called popen(). It works very similar to the system() function except you can read or write to/from the child stdin/stdout.
Example:
int main(int argc, char* argv[])
{
FILE* fChild = popen("logApp.exe", "wb"); // the logger app is another application
if (NULL == fChild) return -1;
fprintf(fChild, "Hello world!\n");
pclose(fChild);
}
Write "man popen" in your console for a full description.
You could use dup2
See Mapping UNIX pipe descriptors to stdin and stdout in C

How to wait till data is written on the other end of pipe

I am developing an application in C.
Parent and child process communicate through pipe.
Before writing to pipe, parent process execute another statements. In sample code, i have used sleep(10) to make delay.
In the child process, it should read the data from the pipe.
But data is not read on the read end of pipe in child process.
int main()
{
int pid;
FILE *fp;
fp = fopen("test.txt","w");
char *buff;
int fd[2];
int count = 0 ;
pipe(fd);
pid = fork();
if(pid == 0)
{
close(fd[1]);
ioctl(fd[0], FIONREAD, &count);
fprintf(fp,"Value of count: %d ",count);
buff = malloc(count);
fprintf(fp,"\n TIME before read: %s",__TIME__);
read(fd[0], buff, count);
fprintf(fp,"\nbuffer: %s\n TIME after read %s", buff, __TIME__);
}
else{
close(fd[0]);
sleep(10); //delay caused by application specific code replaced with sleep
write(fd[1],"THIS is it",10);
}
fclose(fp);
return 0;
}
How to make child process wait till data is written on the other end?
Your pipe is opened in blocking mode, and you do nothing to change that, which is likely what you intended.
However, since the first thing you do is request the size of data waiting on the pipe, then blindly jump into reading that many bytes (which in all likelihood will be zero at the time that code executes since the parent hasn't written anything yet) you don't block, and instead just leave because you requested nothing.
There are a number of ways to do this, including a select-loop. If you would rather block on a read until data is available, then do so on a single byte and fill in the remaining data afterward.
This is by no means an example of how to do this right, but it is a short sample of how you can wait on a single byte, request the read-size of the pipe to get the rest of the data, read it, and continue this until the pipe has no data left and the parent shuts down their end:
I hope you find it helpful.
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main()
{
int pid = 0;
// create pipe pair
int fd[2];
pipe(fd);
pid = fork();
if (pid == 0)
{
// child side
char *buff = NULL;
char byte = 0;
int count = 0;
// close write side. don't need it.
close(fd[1]);
// read at least one byte from the pipe.
while (read(fd[0], &byte, 1) == 1)
{
if (ioctl(fd[0], FIONREAD, &count) != -1)
{
fprintf(stdout,"Child: count = %d\n",count);
// allocate space for the byte we just read + the rest
// of whatever is on the pipe.
buff = malloc(count+1);
buff[0] = byte;
if (read(fd[0], buff+1, count) == count)
fprintf(stdout,"Child: received \"%s\"\n", buff);
free(buff);
}
else
{ // could not read in-size
perror("Failed to read input size.");
}
}
// close our side
close(fd[0]);
fprintf(stdout,"Child: Shutting down.\n");
}
else
{ // close read size. don't need it.
const char msg1[] = "Message From Parent";
const char msg2[] = "Another Message From Parent";
close(fd[0]);
sleep(5); // simulate process wait
fprintf(stdout, "Parent: sending \"%s\"\n", msg1);
write(fd[1], msg1, sizeof(msg1));
sleep(5); // simulate process wait
fprintf(stdout, "Parent: sending \"%s\"\n", msg2);
write(fd[1], msg2, sizeof(msg2));
close(fd[1]);
fprintf(stdout,"Parent: Shutting down.\n");
}
return 0;
}
Output
Parent: sending "Message From Parent"
Child: count = 19
Child: received "Message From Parent"
Parent: sending "Another Message From Parent"
Parent: Shutting down.
Child: count = 27
Child: received "Another Message From Parent"
Child: Shutting down.
I think after
ioctl(fd[0], FIONREAD, &count);
the count is 0.
read(fd[0], buff, count) will get no data.
try
read(fd[0], buff, 10)
The problem is with getting number of bytes written to the pipe. You are getting it right after the fork(). If the read process executes first, it will contain no data (and the count will be zero). If the write process execute first, it will contain some data.
How to make child process wait till data is written on the other end?
Since you opened the pipe in blocking mode, you should read as much data as possible, and not try to get the size of written data.
Here is your modified example that waits for a full message :
#include <stdio.h>
#include <sys/ioctl.h>
int main()
{
int pid;
FILE *fp;
fp = fopen("test.txt","w");
char *buff = malloc(1024);
int fd[2];
int count = 0 ;
pipe(fd);
pid = fork();
if(pid == 0)
{
close(fd[1]);
int i = 0;
while ( i < 10 )
{
fprintf(fp,"\n TIME before read: %s \n",__TIME__);
read(fd[0], buff+i, 1);
++ i;
}
fprintf(fp,"Full message received!\nbuffer: %s\n TIME after read %s\n", buff, __TIME__);
}
else{
close(fd[0]);
sleep(10); //delay caused by application specific code replaced with sleep
write(fd[1],"THIS is it",10);
}
fclose(fp);
return 0;
}

Resources