Reading from a pipe even after the write end is closed - c

Can you please explain me why is the child process able to read even after the parent closes its write end?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd[2];
char buffer[20];
pipe(fd);
if ( fork() == 0 ) //child
{
close(fd[0]); //As it is writing close the read end
strcpy(buffer, "Hello World");
write(fd[1], buffer, sizeof(buffer));
close(fd[1]);
}
else //parent
{
close(fd[1]); //As it is reading closing the write end
while(1)
{
read(fd[0], buffer, sizeof(buffer));
printf("Buffer:%s\n", buffer);
sleep(1);
}
close(fd[0]);
}
}
O/P: Child continuously prints:
Buffer:Hello World
Why is the child able to receive even when the parent terminates? Shouldn't read get EOF?

Why is the child able to receive even when the parent terminates? Shouldn't read get EOF?
At that point the parent process is basically reading nothing (i.e.: read() is returning 0) and printing over and over what it had read in a previous call to read().
You have to look at the value returned by the read() system call. That value is of type int, and basically :
-1: error, something went wrong.
0: nothing else remaining to read, i.e.: EOF (what you were looking for).
Otherwise: the number of bytes read by read() that were stored into buffer.
You can rewrite the parent's while-loop accordingly:
while(1) {
int count = read(fd[0], buffer, sizeof(buffer));
switch (count) {
case 0: // EOF
break;
case -1: // read() error
// ... error handling ...
break;
default: // fine
// count contains the number of bytes read
buffer[count] = '\0'; // NUL character, to indicate the end of string
printf("Buffer:%s\n", buffer);
sleep(1);
}
}

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.

how to establish a non blocking read from unix pipes?

Let‘s assume we have a pipe int InPipe[2];. How can you read the input until the pipe is empty without blocking when the whole available Data input was read?
I know this question has been asked several times, but I couldn’t assemble a suitable function.
This is my Code so far:
int InPipe[2];
char buffer[1024];
int rc;
while (true){
read(InPipe[0], buffer, sizeof(buffer));
fprintf(stdout, “%s“, buffer);
bzero(&buffer, sizeof(buffer)); // Clearing Buffer
}
Any Ideas, Suggestions, Code Snippets
Reading from a pipe
Attempts to read from a pipe that is currently empty block until at
least one byte has been written to the pipe. If the write end
of a pipe is closed, then a process reading from the pipe will
see end-of-file (i.e., read() returns 0) once it has read all remaining
data in the pipe.
taken from linux interface programming.
You cant! the process reading from the pipe will be blocked in this situation.
Due to people comments, i am adding this section:
we can use a pipe to allow communication between two processes. To con-nect two processes using a pipe, we follow the pipe() call with a call to fork(). immediately after the fork(), one process closes its descriptor for the write end of the pipe, and the other closes its descriptor for the read end. For example, if the parent is to send data to the child, then it would close its read descriptor for the pipe, filedes[0], while the child would close its write descriptor for the pipe, filedes[1], then the code for this will be:
int filedes[2];
if (pipe(filedes) == -1) /* Create the pipe */
errExit("pipe");
switch (fork()) /* Create a child process */
{
case -1:
errExit("fork");
case 0: /* Child */
if (close(filedes[1]) == -1) /* Close unused write end */
errExit("close");
/* Child now reads from pipe */
break;
default: /* Parent */
if (close(filedes[0]) == -1) /* Close unused read end */
errExit("close");
/* Parent now writes to pipe */
break;
}
There are a couple of key things mentioned in the comments, i.e. non-blocking IO, and performing the read in its own thread, along with some other suggestions. The example here goes into detail explaining its architecture. Only the code section is reproduced below as I believe it to be a decent illustration of several of these comments. The example code is commented throughout. Read them, they serve as a good tutorial:
// C program to demonstrate use of fork() and pipe()
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
// We use two pipes
// First pipe to send input string from parent
// Second pipe to send concatenated string from child
int fd1[2]; // Used to store two ends of first pipe
int fd2[2]; // Used to store two ends of second pipe
char fixed_str[] = "forgeeks.org";
char input_str[100];
pid_t p;
if (pipe(fd1)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(fd2)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
scanf("%s", input_str);
p = fork(); //Note - the return of fork can be less than, greater
// than or equal to zero. Each is significant in
// knowing how to direct program flow, as shown
// in this section...
if (p < 0)
{
fprintf(stderr, "fork Failed" );
return 1;
}
// Parent process
else if (p > 0)
{
char concat_str[100];
close(fd1[0]); // Close reading end of first pipe
// Write input string and close writing end of first
// pipe.
write(fd1[1], input_str, strlen(input_str)+1);
close(fd1[1]);
// Wait for child to send a string
wait(NULL);
close(fd2[1]); // Close writing end of second pipe
// Read string from child, print it and close
// reading end.
read(fd2[0], concat_str, 100);
printf("Concatenated string %s\n", concat_str);
close(fd2[0]);
}
// child process
else
{
close(fd1[1]); // Close writing end of first pipe
// Read a string using first pipe
char concat_str[100];
read(fd1[0], concat_str, 100);
// Concatenate a fixed string with it
int k = strlen(concat_str);
int i;
for (i=0; i<strlen(fixed_str); i++)
concat_str[k++] = fixed_str[i];
concat_str[k] = '\0'; // string ends with '\0'
// Close both reading ends
close(fd1[0]);
close(fd2[0]);
// Write concatenated string and close writing end
write(fd2[1], concat_str, strlen(concat_str)+1);
close(fd2[1]);
exit(0);
}
}

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.

Send data between pipes in C with While loop

I'm trying to send data between two pipes, that will go from parent->child->parent->child etc and so on until I exit the loop. Right now I'm trying to just pass an integer and increment it for each read done on it. At the moment it seems like each process is only incrementing it's own value and it's read component isn't working correctly. Are my pipes setup wrong?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#define BUFFER_SIZE 25
#define READ 0
#define WRITE 1
int main(void)
{
pid_t pid;
//open two pipes, one for each direction
int mypipefd[2];
int mypipefd2[2];
/* create the pipe */
if (pipe(mypipefd) == -1 || pipe(mypipefd2) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
/* now fork a child process */
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
if (pid > 0) { /* parent process */
int parentVal = 0;
while(1) {
close(mypipefd[READ]); //close read end, write and then close write end
parentVal++;
write(mypipefd[WRITE],&parentVal,sizeof(parentVal));
printf("Parent: writes value : %d\n", parentVal);
close(mypipefd[WRITE]);
close(mypipefd2[WRITE]); //close write end, read, and then close read end
read(mypipefd2[READ],&parentVal,sizeof(parentVal));
printf("Parent: reads value : %d\n", parentVal);
close(mypipefd2[READ]);
}
}
else { /* child process */
int childVal = 0;
while(1) {
close(mypipefd[WRITE]);
read(mypipefd[READ],&childVal,sizeof(childVal));
printf("child: read value : %d\n", childVal);
childVal++;
close(mypipefd[READ]);
close(mypipefd2[READ]); //close read end, write and then close write end
write(mypipefd2[WRITE],&childVal,sizeof(childVal));
printf("child: write value : %d\n",childVal);
close(mypipefd2[WRITE]);
}
}
}
In addition to what Jonathan Leffler said, I want to say that you should add checks to make sure that when read fails, you deal with the condition gracefully.
if (pid > 0) { /* parent process */
int parentVal = 0;
close(mypipefd[READ]); // The parent is not going to read from the first pipe.
// Close the read end of the pipe.
close(mypipefd2[WRITE]); // The parent is not going to write to the second pipe.
// Close the write end of the pipe.
while(1) {
parentVal++;
write(mypipefd[WRITE],&parentVal,sizeof(parentVal));
printf("Parent: writes value : %d\n", parentVal);
// If the chld closes the write end of the second pipe,
// break out of the loop.
if ( read(mypipefd2[READ],&parentVal,sizeof(parentVal)) > 0 )
{
printf("Parent: reads value : %d\n", parentVal);
}
else
{
break;
}
}
close(mypipefd[WRITE]); // Close the write end of the first pipe
close(mypipefd2[READ]); // Close the read end of the second pipe
}
else { /* child process */
int childVal = 0;
close(mypipefd[WRITE]); // The child is not going to write to the first pipe.
// Close the write end of the pipe.
close(mypipefd2[READ]); // The child is not going to read from the second pipe.
// Close the read end of the pipe.
while(1) {
// If the parent closes the write end of the first pipe,
// break out of the loop.
if ( read(mypipefd[READ],&childVal,sizeof(childVal)) > 0 )
{
printf("child: read value : %d\n", childVal);
}
else
{
break;
}
childVal++;
write(mypipefd2[WRITE],&childVal,sizeof(childVal));
printf("child: write value : %d\n",childVal);
}
close(mypipefd[READ]); // Close the read end of the first pipe
close(mypipefd2[WRITE]); // Close the write end of the second pipe
}
Your problem is that you're too enthusiastic about closing file descriptors. (That's a pleasant change from the usual; more often people don't close enough file descriptors.)
Each of the processes should close the ends of the pipes it is not going to use, but should do that before the loop. It should not close the pipes it is reading from or writing to if you want to iterate more than once. Those closes should be after the loop (and could be left out altogether since the program will terminate once the loop terminates, though it is generally better to explicitly close what you explicitly open). You should probably make sure that the loop does terminate (e.g. when the count reaches 1000).

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