Communicating between a child process and a parent process - c

I'm trying to communicate between two processes, a parent process that sends instructions and a child process that returns a response.
void create_player(Game *g, Player *p, int player, char* command) {
int send[2];
int receive[2];
int file;
if(pipe(send)!=0) {
_exit(99);
}
if(pipe(receive)!=0) {
_exit(99);
}
g->player[player].id = fork();
if(g->player[player].id < 0) {
fprintf(stderr, "Unable to start subprocess\n");
fflush(stderr);
exit(5);
}
//Parent process
else if(g->player[player].id>0) {
g->player[player].send = fdopen(send[1], "w");
g->player[player].receive = fdopen(receive[0], "r");
close(send[0]);
close(receive[1]);
//Child process
} else {
close(send[1]);
close(receive[0]);
dup2(send[0], 0);
dup2(receive[1], 1);
close(send[0]);
close(receive[1]);
file = open("/dev/null", O_WRONLY);
for(i =0; i < player; i++) {
fclose(g->player[i].send);
fclose(g->player[i].receive);
}
char width[1024];
char playerId[26];
char numOfPlayers[26];
char seed[1024];
char numOfCarriages[1024];
sprintf(seed, "%d", g->seed);
sprintf(width, "%d", g->numOfCarriages);
sprintf(playerId, "%d", player);
sprintf(numOfPlayers, "%d", g->numOfPlayers);
char* args[] = {command, numOfPlayers, playerId, width, seed, NULL};
execlp(command, command, numOfPlayers, playerId, width, seed, (char*) 0);
_exit(99);
}
When I run the code block to make the child processes, none of the messages are sent through (Parent stdout -> child stdin). I've added some examples to show how I'm handling the messaging. Any help would be greatly appreciated.
In the parent process: Parent Process sends message to child process
//Send message to start the game
void send_startGame(Game *g) {
fprintf(g->player[g->currentPlayer].send, "startGame\n");
fflush(g->player[g->currentPlayer].send);
}
In the child process: child message receives message from parent
void read_message(Game *g) {
char message[2048];
if(fgets(message, 2048, stdin) == NULL) {
fprintf(stderr, "Error in message\n");
}
//Receive start game message
if(strncmp("startGame\n", message, 9)==0){
start_game(g);
}
}

Try to reduce your code, there is wrong close in the child code :
close(send[1]);
dup2(send[0], 0);
close(send[0]);
After the dup2, the filedescriptor send[0] is no more related to the send pipe input, and it could close unexpectly an other filedescriptor in the child process.
Your code doesnot make communication from stdout of parent to stdin of child.
Hereafter a small sample that redirect stdout of parent to input of pipe and output of pipe to stdin of child.
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
int send[2];
if(pipe(send)!=0) {
perror("pipe");
} else {
int pid = fork();
if(pid < 0) {
perror("fork");
}
else if(pid>0) {
//Parent process
close(send[0]); // close pipe input
dup2(send[1], 1); // replace stdout with pipe output
// send message to child
fprintf(stdout, "send to child\n");
fflush(stdout);
} else {
//Child process
close(send[1]); // close pipe output
dup2(send[0], 0); // replace stdin with pipe input
char message[2048];
if(fgets(message, 2048, stdin) != NULL) {
fprintf(stderr, "message from parent:%s", message);
}
}
}
}
Ideone link

Related

Pipe is successfully written to but the target process won't read

I'm trying to create a piped multithreaded, multiprocess program where the parent process will create a thread that will read from a pipe from a sending child and then write to another pipe to the target child. But when the sending child process invokes piped write() to the parent process, the parent process won't read; it continues to block.
Pipe creation and the parent process creating the thread
int value1 = pipe(to_parent[index]);
int value2 = pipe(from_parent[index]);
if(value1 == -1) {
perror("pipe");
continue;
}
if(value2 == -1) {
perror("pipe");
continue;
}
/* fork for every connection to the server*/
int pid = fork();
/*go back to the beginning of loop if fork fails*/
if(pid == -1) {
perror("fork failed");
continue;
}
/* parent process will go back to the beginning of the loop */
if(pid != 0) {
close(from_parent[index][0]);
close(to_parent[index][1]);
pthread_create(&parent_listen_to_child[index], NULL, listen_to_child, &index);
continue;
}
/*PIPE
CHILD => PARENT*/
void * listen_to_child(void * ptr) {
int index = *(int*)ptr;
int index_to_kill;
printf("listen_to_child\n");
read(to_parent[index][0], &index_to_kill, sizeof(int));
printf("talk to child\n");
write(from_parent[index_to_kill][1], &index, sizeof(int));
}
Child processes create the thread that reads from parent through pipe and a thread which would soon write to the parent through the pipe
void respond(int index) {
char buffer[MAX];
int client_socket = clients[index].socket;
char name[MAX_NAME_SIZE];
strcpy(name, get_name(client_socket));
strcpy(clients[index].name, name);
printf("%s has connected to the server\n", name);
print_names();
printf("hello\n");
pthread_create(&command_processor, NULL, receive_command, &index);
/* close pipe ends in child*/
close(from_parent[index][1]);
close(to_parent[index][0]);
pthread_create(&child_listen_to_parent, NULL, listen_to_parent, &index);
pthread_join(child_listen_to_parent, NULL);
pthread_join(command_processor, NULL);
}
/* PIPE
PARENT => CHILD TO CANCEL*/
void * listen_to_parent(void * ptr) {
int index = *(int*)ptr;
int tattle;
printf("listen_to_parent\n");
read(from_parent[index][0], &tattle, sizeof(int));
printf("cancel %s\n", clients[index].name);
pthread_cancel(command_processor);
}
Where the write to the parent process from sending child is invoked
void send_talk(client sender, client target) {
printf("sender: %s\ntarget: %s\n", sender.name, target.name);
int sender_index = get_index(sender.socket);
int target_index = get_index(target.socket);
int write_value;
if(( write_value = write(to_parent[sender_index][1], &target_index, sizeof(int))) != -1) {
printf("write successful: wrote %d bytes\n", write_value);
}
else {
printf("write unsuccessful\n");
}
}

Pipe bc calculator output back to parent fork()

I am trying to get the program to take input from the initial console. Take the arguments and send them to a child fork, run the bc calculator on the data, then return the finished value back to the parent.
I want a user to enter echo "11*13" | ./mycalc
And get the response of: 143
mycalc.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int p[2];
int r[2];
pipe(p);
pipe(r);
pid_t childId = fork();
if(childId == -1)
{
perror("Failed to fork");
return -1;
}
if ( childId == 0)
{
printf("Child Process Has Run\n");
close(p[1]);
close(r[0]);
dup2(p[0], STDIN_FILENO);
dup2(r[1], STDOUT_FILENO);
execlp("bc", "bc", NULL);
} else {
printf("Parent process has run\n");
close(p[0]);
close(r[1]);
write(p[1], argv[1], strlen(argv[1]));
char data[128];
int len = read(r[0], data, 13);
if (len < 0) {
perror("Error reading from child");
}
printf("The data is %s", data);
}
return 1;
}
When I run it I get
Parent process has run
Child Process Has Run
and the cursor just sits there like it is waiting for input, but no matter what I type it does nothing.
The issue that I had was the pipes not being properly closed. After I make sure the pipes closed I was able to continue.

Passing data from a parent to a child and back with Unix C

I am very new to C and am trying to learn how to use pipes to transfer data from a parent process to a child process and vice versa in a Unix environment. In the code below, I receive a command line argument and build a char array based on the argument's value. I then use pipes to pass the char array to a child which will execute a program called vc. This program returns a number result based on the char array. My question is how can I use a second pipe to get the result back to the parent? Also, once the parent has it, how can I print it to the screen since the parent is set to send output to the child? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
int
pfildes[2],
pid,
argNumber;
char
buffer[256],
charString[1024];
//Check for arguments
if(argc != 2) {
printf("No command line arguements given.\n");
argNumber=10; //default
}
else
argNumber=atoi(argv[1]);
//***********************************
//Build charString based on argNumber
//***********************************
//create pipes
if(pipe(pfildes) == -1) {
//error occured when creating pipe
perror("demo");
exit(1);
}
//create child process
if((pid=fork()) < 0) {
//error occured when forking child
perror("demo");
exit(1);
}
else if(pid > 0) {
//parent process
close(pfildes[0]);
dup2(pfildes[1],1);
printf("%s", charString);
close(pfildes[1]);
perror("demo");
_exit(1);
}
else {
//child process
close(pfildes[1]);
dup2(pfildes[0],0);
execlp("/usr/bin/vc","vc", NULL);
close(pfildes[0]);
perror("demo");
exit(1);
}
while(wait(NULL) >0);
return 0;
}
You can use socketpair() instead of pipe() to generate a bidirectional communication channel between the parent and child process:
//...
if (socketpair(PF_UNIX, SOCK_STREAM, 0, pfildes) == -1) {
//error occured when socket pair
perror("demo: socketpair");
exit(1);
}
//..
In the child process, you can dup() one of the pair into both input and output before calling exec():
//...
else {
//child process
close(pfildes[1]);
dup2(pfildes[0],0);
dup2(pfildes[0],1);
dup2(pfildes[0],2);
close(pfildes[0]);
execlp("/usr/bin/vc","vc", NULL);
perror("demo: child exec");
exit(1);
}
//...
In the parent process, you can create a FILE * from a file descriptor using fdopen(), so you don't need to dup() over your existing stdout file descriptor:
//...
else if(pid > 0) {
//parent process
close(pfildes[0]);
FILE *to_child = fdopen(dup(pfildes[1]), "w");
FILE *from_child = fdopen(dup(pfildes[1]), "r");
close(pfildes[1]);
fprintf(to_child, "%s", charString);
while (fgets(buf, sizeof(buf), from_child) != NULL) {
//...do something with output
}
//...
} else { //...

How to loop through stdin & pipe output to a child execl command in C?

I have been trying to figure out how to loop through stdin from a file, then send it to a child process who sorts int using execl(). The code below works in that it takes the file & sorts the lines, but I am not seeing the "end of sentence" debug string I have added. Somehow this part of the code is being bypassed. I could use some help understanding the flow of data as it comes in from the file, then gets printed out to the screen.
int main(int argc, char *argv[])
{
pid_t p;
int status;
int fds[2];
FILE *writeToChild;
char word[50];
if(pipe(fds) == -1) {
perror("Error creating pipes");
exit(EXIT_FAILURE);
}
switch(p = fork()) {
case 0: //this is the child process
close(fds[1]); //close the write end of the pipe
execl("/usr/bin/sort", "sort", (char *) 0);
break;
case -1: //failure to fork case
perror("Could not create child");
exit(EXIT_FAILURE);
default: //this is the parent process
close(fds[0]); //close the read end of the pipe
writeToChild = fdopen(fds[1], "w");
wait(&status);
break;
}
while (fscanf(stdin, "%s", word) != EOF) {
//the below isn't being printed. Why?
fprintf(writeToChild, "%s end of sentence\n", word);
}
return 0;
}
Your primary problem is that you have the wait() in the wrong place. You wait for the child to die before you've written anything to it. You also have a secondary problem that don't redirect the read end of the pipe to the sort process's standard input.
You're not closing fds[0] in the child; cleanliness suggests that you should. You do need to fclose(writeToChild) before waiting; the sort won't stop until the parent has closed the pipe to the child.
These changes (and a few other ones) lead to:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t p;
int status;
int fds[2];
FILE *writeToChild;
char word[50];
if (pipe(fds) == -1)
{
perror("Error creating pipes");
exit(EXIT_FAILURE);
}
switch (p = fork())
{
case 0: //this is the child process
close(fds[1]); //close the write end of the pipe
dup2(fds[0], 0);
close(fds[0]);
execl("/usr/bin/sort", "sort", (char *) 0);
fprintf(stderr, "Failed to exec sort\n");
exit(EXIT_FAILURE);
case -1: //failure to fork case
perror("Could not create child");
exit(EXIT_FAILURE);
default: //this is the parent process
close(fds[0]); //close the read end of the pipe
writeToChild = fdopen(fds[1], "w");
break;
}
if (writeToChild != 0)
{
while (fscanf(stdin, "%49s", word) != EOF)
{
//the below isn't being printed. Why?
fprintf(writeToChild, "%s end of sentence\n", word);
}
fclose(writeToChild);
}
wait(&status);
return 0;
}

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