Can I use pipe as read at parent and write in child? - c

I'm now learning how to use pipes correctly. I found examples only for write in parent and read in child, but I want to know how can I do it reverse. I tried like this:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
int main(){
int p1[2], p2[2];
char original[]="This is a string\n ";
pid_t child2;
pid_t child=fork();
if (child>0)
{
child2 = fork();
if(child2>0){
wait();
printf("I'm the parrent.\n");
close(p1[1]);
close(p2[1]);
printf("Parrent read p1:\n");
if (read(p1[0], original, sizeof(original)) == -1)
perror("read() error in parent p1");
else printf("parent read '%s' from pipe 1\n", original);
printf("Parrent read p2:\n");
if (read(p2[0], original, sizeof(original)) == -1)
perror("read() error in parent p2");
else printf("parent read '%s' from pipe 2\n", original);
}
else{
printf("Child2 \n");
pipe(p2);
close(p2[0]);
if (write(p2[1], original, sizeof(original)+1) == -1)
perror("write() error in child2");
//close(p2[1]);
}
}
else
{
printf("Child1 \n");
pipe(p1);
close(p1[0]);
if (write(p1[1], original, sizeof(original)+1) == -1)
perror("write() error in child1");
//close(p1[1]);
}
return 0;
}
But this way give to me error at reading in parent. read() error in parent p1: Bad file descriptor both times, at p1 and also at p2. So, can I do this this way or not? Or this is just something trivial error?

As already said you just need to invert the indexes for closing the pipes and the read/write.
Your code was almost correct. Two things were wrong: on the parent you were first closing the pipes and then calling pipe(): it should be the other way round: first you create both of the pipes and then close the corresponding element, all in the parent.
Secondly you should call wait after setting the pipes otherwise it does not work. Guessing you want to wait for all the children you should call wait(NULL). I do not know what you meant with wait().
The complete code:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(){
int p1[2], p2[2];
char original[]="This is a string\n ";
pid_t child2;
pid_t child=fork();
if (child>0)
{
child2 = fork();
if(child2>0){
printf("I'm the parrent.\n");
pipe(p1); //ADDED
pipe(p2); //ADDED
close(p1[1]);
close(p2[1]);
wait(NULL); //DON'T GET IT WHY? if u want to wait all children,
//wait after setting the pipes.
printf("Parrent read p1:\n");
if (read(p1[0], original, sizeof(original)) == -1)
perror("read() error in parent p1");
else printf("parent read '%s' from pipe 1\n", original);
printf("Parrent read p2:\n");
if (read(p2[0], original, sizeof(original)) == -1)
perror("read() error in parent p2");
else printf("parent read '%s' from pipe 2\n", original);
}
else{
printf("Child2 \n");
//pipe(p2); ERROR HERE
close(p2[0]);
if (write(p2[1], original, sizeof(original)+1) == -1)
perror("write() error in child2");
//close(p2[1]);
}
}
}

Related

close pipe from parent and child process

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main() {
int p[2];
pipe(p);
if (fork() == 0) {
// child
/*#0*/ close(p[1]);
int received = -1;
while (read(p[0], &received, 4) != 0) {
printf("receive integer: %d\n", received);
received = -1;
}
printf("child exit\n");
exit(0);
} else {
// parent
/*#1*/ close(p[0]);
int sent = 42;
write(p[1], &sent, 4);
/*#2*/ close(p[1]);
printf("wait for child\n");
wait(0);
}
printf("finished\n");
}
I'm trying to understand fork and pipe in C. This program fork a child process, which receive an integer from parent process then exit when pipe closed. When executing, it prints
wait for child
receive integer: 42
child exit
finished
Yet the while loop got stuck after close(p[1]); at position #0 removed: that read would infinitely wait for an incoming variable from the pipe and never detect the pipe closed.
Can someone explain to me why p[1] has to be closed by both parent (position #2) and child (position #0) process?
Here is the code (from Linux manual page) with comments at the bottom of the code.
https://man7.org/linux/man-pages/man2/pipe.2.html
At /#2/ close(pipefd[1]), the comment states that "Reader will see EOF". It means there is nothing to read into child process anymore and then the statement "read(p[0], &received, 4)" will return 0. In the Linux manaul page https://man7.org/linux/man-pages/man2/read.2.html
states that "On success, the number of bytes read is returned (zero indicates end of file)"
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else {/* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
/*#2*/ close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}

C Programming: Segmentation Fault (Core Dumped)

The program i am trying to write is trying to demonstrate how IPC works on Linux, but i keep getting a core dump error. It compiles fine and will run up until the last output statement in the parent process.
My code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <err.h>
#include <sysexits.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#define SHM_SIZE 15
int main (int argc, char ** argv[]) {
pid_t pid; //pid variable of type pid
int shmid; //shared memory id
int key = 1776; //randomly chosen key
char *shm; //shared memory name
int pipefd[2];
char buff;
pid = fork(); //creating child process
pipe(pipefd); //creating pipe
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return -1;
} else if (pid == 0) {
shmid = shmget(key, SHM_SIZE, 0);
shm = shmat(shmid, 0, 0);
char *n = (char *) shm;
printf("hello i am the child process. my pid is %d. what is your name?: ", getpid());
scanf("%s", n);
printf("\n");
///////////////////////////////////////////////////////////////////////////////////////
close(pipefd[1]);
printf("pipe opened on child end");
printf("\n");
while(read(pipefd[0], &buff, 1) > 0) {
write(1, &buff, 1);
}
write(1, "\n", 1);
close(pipefd[0]);
printf("pipe successfully closed");
printf("\n");
exit(EXIT_SUCCESS);
} else {
shmid = shmget(key, SHM_SIZE, 0777 | IPC_CREAT);
shm = shmat(shmid, 0, 0);
wait(NULL);
printf("\nThis is Child's Parent. My pid is %d. Nice to me you %s.\n", getpid(), shm);
printf("\n");
//////////////////////////////////////////////////////////////////////////////////////
close(pipefd[0]);
printf("pipe open on parent end");
printf("\n");
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]);
printf("pipe successfully closed");
wait(NULL);
exit(EXIT_SUCCESS);
}
return 0;
}
Does it have something to do with my args[]? Such as could i be accessing memory out of reach? Or am trying to access some invalid pointer?
Many Thanks!
You have several problems in your code
Create the pipe before the fork. You create the pipe twice, once for
the parent process and one for the child process. That makes no sense, the pipe
that the child created cannot be used by the parent. The pipe must already
exists so that the child inherits the file descriptors when the child is
created.
Usually the parent creates the shared memory and the child gets the shmid
from the parent when it does the fork. Otherwise you will have to synchronize
the child and parent. So I would put the creation of the shared memory before
the fork, so that the child inherits the shmid from the parent.
In the line char *n = (char *) shm; the cast is not needed, shm is
already a char*.
In the parent block after the fork, you do wait(NULL); and then proceed to
write into the pipe. That makes no sense and you block both parent and child.
The child blocks on read because the parent hasn't send anything through the
pipe, yet. And the parent blocks on wait, because the child never exits and thus
cannot send anything through the pipe. The parent must first send data
through the pipe, then wait for the child to exit.
In the child block you do scanf("%s", n);, you are not protecting you
against buffer overflows. scanf("%14s", n) would be better. Also you are not
checking if scanf read anything at all. If the user presses
CtrlD then stdin is closed, scanf fails. In that case
n might not be '\0'-terminated and this would lead to undefined behaviour
when the parent tries to print it. So it would be better:
if(scanf("%14s", n) != 1) // avoid buffer overflow
{
fprintf(stderr, "Child: cannot read from stdin\n");
n[0] = 0; // 0-terminating
}
In the parent block after the fork, you do wait twice, why?
Your main is wrong, it should be
int main(int argc, char **argv);
The parent sends the contents of argv[1] to the child through the pipe, but
you fail to check if argv[1] is not NULL. Use this at the start of the
program:
if(argc != 2)
{
fprintf(stderr, "usage: %s string\n", argv[0]);
return 1;
}
So the correct version would be:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <err.h>
#include <sysexits.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#define SHM_SIZE 15
int main (int argc, char **argv) {
pid_t pid; //pid variable of type pid
int shmid; //shared memory id
char *shm; //shared memory name
if(argc != 2)
{
fprintf(stderr, "usage: %s string\n", argv[0]);
return 1;
}
int pipefd[2];
char buff;
// create shared memory before the fork,
// otherwise you will need to syncronize parent
// and child
pipe(pipefd); //creating pipe before the fork
// parent creates shared memory, child inherits shmid
// after fork
shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
pid = fork(); //creating child process
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1; // return -1 would be the same as return 255
} else if (pid == 0) {
shm = shmat(shmid, 0, 0);
char *n = shm; // shm is already a char*
printf("hello i am the child process. my pid is %d. what is your name?: ", getpid());
if(scanf("%14s", n) != 1) // avoid buffer overflow
{
fprintf(stderr, "Child: cannot read from stdin\n");
n[0] = 0; // 0-terminating
}
printf("\n");
///////////////////////////////////////////////////////////////////////////////////////
close(pipefd[1]);
printf("pipe opened on child end");
printf("\n");
printf("Parent sends: ");
fflush(stdout);
while(read(pipefd[0], &buff, 1) > 0) {
write(1, &buff, 1);
}
write(1, "\n", 1);
close(pipefd[0]);
printf("pipe successfully closed");
printf("\n");
exit(EXIT_SUCCESS);
} else {
shm = shmat(shmid, 0, 0);
close(pipefd[0]);
printf("pipe open on parent end");
printf("\n");
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]);
printf("pipe successfully closed");
// not we wait for child to exit
wait(NULL);
printf("\nThis is Child's Parent. My pid is %d. Nice to me you %s.\n", getpid(), shm);
printf("\n");
//////////////////////////////////////////////////////////////////////////////////////
exit(EXIT_SUCCESS);
}
return 0;
}
And the output is:
$ ./b "message to child: stop playing video games!"
pipe open on parent end
hello i am the child process. my pid is 10969. what is your name?: Pablo
pipe opened on child end
Parent sends: message to child: stop playing video games!
pipe successfully closed
pipe successfully closed
This is Child's Parent. My pid is 10968. Nice to me you Pablo.
You are reading and writing from the same end of the pipe you create. Common practice is to read from end [1] and write to end [0]. Tell me if that helps. Additionally, it is also common practice to not have too much going on between the child and parent processes. Attempting to execute code in between segments (parent and child) usually ends up with a segmentation fault, even if your code compiles.

How to Create IPC (Interprocess Communication) C programme to create with two child process

I want to create a IPC c program to create one parent and two child's processes. My code is:
#include <stdio.h>
void main()
{
int pid, status;
pid = fork();
if(pid == -1) {
printf(“fork failed\n”);
exit(1);
}
if(pid == 0) { /* Child */
if (execlp(“/bin/ls”, “ls”, NULL)< 0) {
printf(“exec failed\n”);
exit(1);
}
}
else { /* Parent */
wait(&status);
printf(“Well done kid!\n”);
exit(0);
}
}
I want to show you an other code snippet to create one parent and two child process. This is what I am looking for. Now I want to write shell script for IPC, first take look of this code.
Note: there is an other code with same logic but different process names UP, uc1, uc2 e.g in this way we have two parent VP and UC and there childs vp1 vp2 and uc1 uc2.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_BUF 1024
int main(){
int mypipe_c1[2];
int ret_c1;
char buf_c1[6];
ret_c1 =pipe(mypipe_c1);
int mypipe_c2[2];
int ret_c2;
char buf_c2[6];
ret_c2 =pipe(mypipe_c2);
if(ret_c1 == -1)
{
perror("pipe");
exit(1);
}
pid_t vc1;
pid_t vc2;
vc1 = fork ();
if (vc1 == 0)
{
read(mypipe_c1[0], buf_c1 , 37);
printf("PIPE1 :%s\n", buf_c1);
printf (" vc1 : I'm the child! My pid is (%d)\n", getpid ());
close(ret_c1);
int fd;
char * fifo1 = "/tmp/fifo1";
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(fifo1, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("FIFO1: %s\n", buf);
close(fd);
exit(0);
}
if(vc1 < 0)
{
perror ("Ouch! Unable to fork() child process!\n");
exit (1);
}
vc2 = fork ();
if (vc2 == 0)
{
printf ("vc2 : I'm the child! My pid is (%d)\n", getpid ());
read(mypipe_c2[0], buf_c2 , 37);
printf("PIPE2 %s\n", buf_c2);
int fd;
char * fifo2 = "/tmp/fifo2";
/* create the FIFO (named pipe) */
mkfifo(fifo2, 0666);
/* write "Hi" to the FIFO */
fd = open(fifo2, O_WRONLY);
write(fd, " assignment VU 2 ", sizeof(" assignment VU 2 "));
close(fd);
/* remove the FIFO */
unlink(fifo2);
exit(0);
}
else if (vc2 < 0)
{
perror ("Ouch! Unable to fork() child process!\n");
exit (1);
}
printf ("I'm the parent! My pid is (%d)!\n",getpid());
write(mypipe_c1[1], "I am going to close you carry on UC1 \n", 37);
write(mypipe_c2[1], "I am going to close you carry on UC2 \n", 37);
exit(0);
}
Now I want shell script such that VP and UP should be started when users types … script.sh start VP or UP. vc1, vc2, uc1,uc2 should be stoppable only using script.sh stop vc1 or vc2 or uc1 or uc2
script.sh connect command should create two fifo and connect processes as shown in figure.
So you are asking for methods for IPC, with the sample code you provided, I think the best one is the use of pipes.
From the pipe() man page:
A pipe is a unidirectional data channel that can be used for interprocess communication
Basically, it is handled like a pair of file descriptors. First, you must init the pipe, and then create the childs using the fork() call, so both parents and childs share the resource. Then, using write and read methods, you can send data between them.
In this example I create a child which reads some data from the parent process:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int pid;
char buffer[255];
int fd[2]; // channel 0 for reading and 1 for writing
pipe(fd);
pid = fork();
if(pid == 0) {
close(fd[1]); // close fd[1] since child will only read
read(fd[0], &buffer, sizeof(buffer));
close(fd[0]);
exit(0);
} else { // parent
close(fd[0]) // close fd[0] since parent will only write
// init buffer contents
write(fd[1], &buffer, sizeof(buffer));
close(fd[1]);
}
return 0;
}
As you can see pipe creates a pair of file descriptors, one for writing (number 1) and one for reading (number 0).
In my sample code, the child process closes the writing one, since it will only read, and the parent closes the reading one, since it will only write data.
Note that pipes are unidirectional, so if you want that both the childs and the parent write and read data from it, you should create two pipes (so 4 file descriptors) for each of the childs. An example of how to handle that situation:
int pipeA[2], pipeB[2];
pid = fork();
if (pid == 0) { // child will write to pipeB and read from pipeA
close(pipeA[1]); // closing pipeA writing fd
close(pipeB[0]); // closing pipeB reading fd
write(pipeB[1],&buffer, sizeof(buffer));
read(pipeA[0], &buffer2, sizeof(buffer2));
close(pipeA[0]);
close(pipeB[1]);
exit(1);
} else { // parent will write to pipeA and read from pipeB
close(pipeA[0]); // closing pipeA reading fd
close(pipeB[1]); // closing pipeB writing fd
read(pipeB[0], &buffer, sizeof(buffer));
write(pipeA[1], &buffer2, sizeof(buffer2));
close(pipeA[1]);
close(pipeB[0]);
}
If you want more info about pipes you can check the man page here.
Also, other simple ways of IPC would be the use of Unix Sockets, although I think that for the example you presented pipes will be enough.
You'r code create one parent and one child, not two child, so you need to add another fork into child block :
#include <stdio.h>
void main()
{
int pid,status;
pid = fork();
if(pid == -1) {
printf(“fork failed\n”);
exit(1);
}
if(pid == 0) { /* Child */
fork();// another child
if (execlp(“/bin/ls”, “ls”, NULL)< 0) {
printf(“exec failed\n”);
exit(1);
}
}
else { /* Parent */
wait(&status);
printf(“Well done kid!\n”);
exit(0);
}
}

creating pipe between father and child process

I'm trying to create a pipe between father and child process.
in this pipe, the child process will write data and the father will read and print it.
I don't know why but if I enter a big string the data got wrong, for strings with +- 7 words it still do fine.
I guess it is about the size of the buffer but can't fix it.
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* in this code i will make a child process with fork command
then i will create pipe using pipe commands.
i will transfer data from the child process to the father process
omriziner code
*/
void main(int argc,char *argv[])
{
if(argc < 2){
printf("prototype error \n<Enter any data you wana write> \n");
return;
}
int fd[2]; // creating array with 2 places for 2 fd'stdio
// fd[0] is set to read file in the pipe
//fd[1] is set to write file in the pipe
int piperes;
pid_t childpid;
char buff[5];
char * data = "learning to the exam";
printf("father pid %d:\n",getpid());
printf ("size of data is %d \n",(int)sizeof(argv[1]));
printf ("size of buff is %d \n",(int)sizeof(buff));
piperes = pipe(fd);
if(piperes < 0){
perror("PIPE ERR");
exit(1);
}
printf("Pipe succeed \n");
if((childpid = fork()) == -1){ // fork will create a child process
perror("FORK ERR");
exit(1);
}
// when fork suceed - the pid of the child will return in the parent and 0 will return in the child
// when fork fail - the pid will be -1
printf("Fork succeed, fork return is %d and process pid is %d :\n",childpid,getpid());
if(childpid == 0){ // if pid zero , wer in the child prcs
close(fd[0]);
write(fd[1],argv[1],sizeof(argv[1])); // send data to the write fd of the pipe
printf("data was written to fd[1] by pid : %d \n",getpid());
exit(0);
}
else{ // in this case, we're in the father process
close(fd[1]);
read(fd[0],buff,sizeof(argv[1])+1);
printf("Recived data is ''%s''", buff);
printf("By pid : %d \n",getpid());
exit(1);
}
}
sizeof(argv[1])
This does not do what you think it does.
sizeof is evaluated at compile-time1, and in this case will return 8 (assuming you're on a 64-bit machine), because argv[1] is a pointer.
Because you want the length of the string (which can only be known at run-time), you should instead use:
strlen(argv[1])
1 - There are cases where sizeof is evaluated at run-time. This is not one of them.

pipe call and synchronization

I'm experimenting some problems with this code:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 30
#define Error_(x) { perror(x); exit(1); }
int main(int argc, char *argv[]) {
char message[SIZE];
int pid, status, ret, fd[2];
ret = pipe(fd);
if(ret == -1) Error_("Pipe creation");
if((pid = fork()) == -1) Error_("Fork error");
if(pid == 0){ //child process: reader (child wants to receive data from the parent)
close(fd[1]); //reader closes unused ch.
while( read(fd[0], message, SIZE) > 0 )
printf("Message: %s", message);
close(fd[0]);
}
else{//parent: writer (reads from STDIN, sends data to the child)
close(fd[0]);
puts("Tipe some text ('quit to exit')");
do{
fgets(message, SIZE, stdin);
write(fd[1], message, SIZE);
}while(strcmp(message, "quit\n") != 0);
close(fd[1]);
wait(&status);
}
}
Code works fine but I can't explain why! There is no explicit sync between parent and child processes. If the child-process executes before parent, read must return 0 and the process ends, but for some reason it waits for the parent execution. How do you explain this? Maybe I'm missing something.
(Edited)
Since you didn't use O_NONBLOCK in pipe2, read is blocking by default. Therefore it waits until data are written into the pipe.

Resources