In78 In78 - 1 month ago 12
C Question

IPC using fork() and pipe()

I am trying to simulate conversation between a caller and a receiver using pipes. I am forking a process and making the parent process the receiver and the child process the caller.

Here is the code:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>

#define BUF_LEN 25
#define READ_END 0
#define WRITE_END 1

int main()
{
int fd[2];
if (pipe(fd) == -1) {
fprintf(stderr, "Pipe failed");
return 1;
}

pid_t pid = fork();

if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}

// the parent process is the receiver
if (pid > 0) {
close(fd[WRITE_END]);
char buffer[BUF_LEN + 1] = "";
do {
read(fd[READ_END], buffer, sizeof buffer);
if (strcmp(buffer, "")) {
printf("Received %s\n", buffer);
}
strcpy(buffer, "");
} while (strcmp(buffer, "Bye!"));
close(fd[READ_END]);
} else {
close(fd[READ_END]);
// const char *msg = "Hello";
char buffer[BUF_LEN + 1] = "";
bool end_call = false;
do {
printf("Caller: ");
fgets(buffer, sizeof buffer, stdin);
if (strcmp(buffer, "Bye!")) {
end_call = true;
}
// printf("Sent %s\n", buffer);
write(fd[WRITE_END], buffer, strlen(buffer) + 1);
} while (!end_call);
close(fd[WRITE_END]);
}
return 0;
}


But when I run this, I get this unexpected output:

Caller: Hi
Received Hi

HI
Hello
Bye!
^C


The receiver stops working, it is not receiving the inputs I give. Also there are extra newlines appearing in the output. Why is this occuring?

Edit:
As pointed by out Dmitri, I have changed the strcmp test in the caller and the printf statement in the receiver.

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>

#define BUF_LEN 25
#define READ_END 0
#define WRITE_END 1

int main()
{
int fd[2];
if (pipe(fd) == -1) {
fprintf(stderr, "Pipe failed"); return 1; }

pid_t pid = fork();

if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}

// the parent process is the receiver
if (pid > 0) {
close(fd[WRITE_END]);
char buffer[BUF_LEN + 1] = "";
do {
read(fd[READ_END], buffer, sizeof buffer);
if (strcmp(buffer, "")) {
printf("Received %s", buffer);
}
strcpy(buffer, "");
} while (strcmp(buffer, "Bye!"));
close(fd[READ_END]);
} else {
close(fd[READ_END]);
// const char *msg = "Hello";
char buffer[BUF_LEN + 1] = "";
bool end_call = false;
do {
printf("Caller: ");
fgets(buffer, sizeof buffer, stdin);
if (!strcmp(buffer, "Bye!")) {
end_call = true;
}
// printf("Sent %s\n", buffer);
write(fd[WRITE_END], buffer, strlen(buffer) + 1);
} while (!end_call);
close(fd[WRITE_END]);
}
return 0;
}


But it is still not exiting after receiving "Bye!".

Caller: hi
Received hi
Caller: Hello
Received Hello
Caller: Bye!
Received Bye!
Caller: Bye!
Received Bye!
Caller: ^C

Answer

The strcmp() returns 0 on success. But there are also several other problems with your code:

  1. The string will never be equal to "Bye!", there is going to be a new line attached as well as the null character indicating the end of string (total of 6 chars).

  2. The pipes use streams not "packets" you never know how many bytes you will receive from one call read(). It might be incomplete string or if the data is sent very fast you might get 2 strings glued to each other. You need to implement your own "protocol" to parse the data out of the string.

  3. You are not checking if the pipe was closed on the other side (read would return 0)

  4. You get extra new line in the output because it is attached to the string read by fgets() and

  5. Output may be messed up because you have no control on when processes flush to stdout (sort o a racing condition but it will not crash).