I am trying to implement a small IPC in C, but I have an issue that I can't solve.
My main process have two children, child A and child B; Child A gets created first.
I have two pipes to pass information to these processes, pipefd and pipefd2.
First, parent process reads a file's content, and writes to both pipes these two values:
1-length of the string
2-string itself
Once they get the length of string, they create a char array with the given length, and then read the string into this array.
Then both children read from their pipes. Child B can get these values correctly from the pipe, but child A gets 0 as size.
Here's my code, thanks for your time!
Output :
Child A here, input read, size is: 0
Size is 45169child reads input, size : 45169
Child B here, input read, size is: 45169
//
// Created by Dilara on 16.02.2020.
//
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MESSAGESIZE 10
#define READ_END 0
#define WRITE_END 1
int fsize(FILE *fp){
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
int sz=ftell(fp);
fseek(fp,prev,SEEK_SET); //go back to where we were
return sz;
}
void writeToPipe(int fd[2], char string[], long stell){
close(fd[READ_END]);
write(fd[WRITE_END], stell, sizeof(stell));
write(fd[WRITE_END], string, strlen(string)+1);
close(fd[WRITE_END]);
}
static void readFromPipe(int pipefd[2], char input[],long size){
// wait(NULL);
close(pipefd[WRITE_END]);
read(pipefd[READ_END], input, size);
printf("child reads input, size : %d \n",size);
close(pipefd[READ_END]);
}
static long readSize(int pipefd[2]){
long size;
close(pipefd[WRITE_END]);
read(pipefd[READ_END], size, sizeof(size));
printf("Size is %d",size);
close(pipefd[READ_END]);
return size;
}
int main()
{
int pipefd[2];
int pipefd2[2];
int childA_pid;
int childB_pid;
if (pipe(pipefd) == -1)
{
perror(" pipe");
return 0;
}
if (pipe(pipefd2) == -1)
{
perror(" pipe");
return 0;
}
childA_pid = fork();
if(childA_pid == 0){
//childA
long SIZE = readSize(pipefd);
char input[SIZE];
readFromPipe(pipefd, input, SIZE);
printf("Child A here, input read, size is: %d \n",SIZE);
}
else{
childB_pid = fork();
if(childB_pid == 0){
long SIZE = readSize(pipefd2);
char input[SIZE];
readFromPipe(pipefd2, input, SIZE);
printf("Child B here, input read, size is: %d \n",SIZE);
}else{
//parent
char *buffer;
FILE *fp = fopen("try.txt", "r");
if (fp != NULL)
{
fseek(fp, 0L, SEEK_END);
long stell = ftell(fp);
rewind(fp);
char str[stell];
buffer = (char *)malloc(stell);
if (buffer != NULL)
{
//fread(buffer, stell, 1, fp);
fread(str,stell,1, fp);
// printf("%s", str);
fclose(fp);
fp = NULL;
free(buffer);
}
printf("SIZE: %d", stell);
writeToPipe(pipefd2, str,stell);
writeToPipe(pipefd, str,stell);
}
}
}
return 0;
}
write(fd[WRITE_END], stell, sizeof(stell));
I think your code lacks an ampersand here. Instead of the stell variable you should use its address:
write(fd[WRITE_END], &stell, sizeof(stell));
Related
This is all done on a linux machine.
I have a pipe, fp, sending from the parent to the child the name of a file using a buffer.
The buffer is:
char buf[20];
the child has the following code:
{
//we are in the child
close(fp[1]);
int fd;
read(fp[0],buf,20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
else exit(0);
close(fp[0]);
}
Even if I type in the name of a file that exists, I'm getting the exit status of 1. So...
this unfortunately doesn't work. The issue is that the buff itself not only does '\n', but also also plenty of '\0', all of which don't actually exist in the name of real file. I've tried replacing the '\n' with a '\0' but that also doesn't work. How can I solve this?
Here's the whole code.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
int main(){
int fp[2];
if (pipe(fp) < 0){
printf("error creating pipe\n");
exit(-1);
}
int id;
char buf[20];
id=fork();
//father process here --------------------------------
if (id!=0){
close(fp[0]); //closing read
printf("program name: ");
fflush(stdout);
read(STDIN_FILENO,buf,20);
write(fp[1],buf,20);
int waitstatus, exitcode;
wait(&waitstatus);
//check if exited correctly
if (WIFEXITED(waitstatus))
exitcode = WEXITSTATUS(waitstatus);
else
{
printf("Bad exit\n");
return 0;
}
if (exitcode==1) printf("error, file doesn't exist\n");
else printf("file does exist\n");
close(fp[1]);
}
//child process here --------------------
else{
close(fp[1]); //closing write
int fd;
read(fp[0],buf,20);
//write(STDOUT_FILENO, buf, 20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
exit(0);
close(fp[0]);
}
}
You send the full buf which contains a newline and other indeterminate values. You need to remove the newline and I suggest that you only send what you need on the receiving end.
printf("program name: ");
fflush(stdout);
if(fgets(buf, sizeof buf, stdin)==NULL) return 1;
size_t len = strlen(buf);
buf[len - 1] = '\0'; // remove the newline
write(fp[1], buf, len); // only send what you actually need
I've been stuck on getting piping to work between two programs for the last couple of hours and I'm stuck and not sure if I'm doing something wrong. The idea of my program is that I'm going to use interface.c to open a pipe, and then execute db.c. I want to use two pipes to communicate between the two different programs. Now, with interface.c being the 'parent' and db.c being the 'child', I'm not sure if I'm passing in the parameters to my pipe correctly via the execl command. Everything compiles correctly, but when I try to run the interface program, I'm getting an error stating: 'Bad File Number.' Is it possible that I'm not using pipes correctly? Currently, I'm just trying to get my program to send an integer, value, over the pipe to db.c. Any help would be much appreciated.
Code for interface.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/wait.h>
//PIPES:
//
//Parent: reads from P1_READ, writes on P1_WRITE
//Child: reads from P2_READ, writes on P2_WRITE
#define P1_READ 0
#define P2_WRITE 1
#define P2_READ 2
#define P1_WRITE 3
// the total number of pipe *pairs* we need
#define NUM_PIPES 2
int main(int argc, char *argv[])
{
//Create Pipe Array
int fd[2*NUM_PIPES];
//For Parameter Passing:
char param0[20]; //P1_Read
char param1[20]; //P2_Write
char param2[20]; //P2_Read
char param3[20]; //P1_Write
snprintf(param0, sizeof(param0), "%d" , fd[0]);
snprintf(param1, sizeof(param1), "%d" , fd[1]);
snprintf(param2, sizeof(param2), "%d" , fd[2]);
snprintf(param3, sizeof(param3), "%d" , fd[3]);
//Variables
pid_t pid;
int val = 42;
//Allocate the PIPES
for (int i=0; i<NUM_PIPES; ++i)
{
if(pipe(fd+(i*2)) < 0)
{
perror("Failed to allocate the pipes");
exit(EXIT_FAILURE);
}
}
//If the fork of the program does not work:
if ((pid = fork()) < 0)
{
perror("Failed to fork process");
return EXIT_FAILURE;
}
if(pid == 0)
{ //Child Process
execl("./db", "db", param0, param1, param2, param3, (char *)NULL);
}
else
{ //Parent Process
//SENDING VALUES HERE
close(fd[P2_READ]);
close(fd[P2_WRITE]);
printf("Interface is sending|%d| to DB\n", val);
if(write(fd[P1_WRITE],&val, sizeof(val)) != sizeof(val))
{
perror("Interfae failed to send value to DB");
exit(EXIT_FAILURE);
}
}
return 0;
}
This is for db.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
//Typedef-Class-
typedef struct Information
{
int accountId;
int checkNumber;
int date;
float amount;
} Information;
int main(int argc, char *argv[])
{
//For Input
//Account Data
Information acctData[25];
int dataStorageLooper = 0; //How many db entries
//For File Input
int aVal;
int bVal;
int cVal;
float dVal;
//Prepare for file input:
FILE * fp;
fp = fopen ("accountData.txt", "r");
//Reads Input
while(1)
{
if (fscanf(fp, "%d %d %d %f", &aVal, &bVal, &cVal, &dVal)!=4)
{
break;
}
//Puts data into appropriate arrays
acctData[dataStorageLooper].accountId= aVal;
acctData[dataStorageLooper].checkNumber= bVal;
acctData[dataStorageLooper].date= cVal;
acctData[dataStorageLooper].amount= dVal;
dataStorageLooper++;
}
//Decrement index to point to last item
dataStorageLooper--;
//Displays all values
printf("\nDisplaying AccountData.txt\n");
for( int i = 0; i < dataStorageLooper; i++)
{
printf("Line|%d|: Account|%d|: Check|%d|: Date|%d|: Amount|%.2f|\n",i,acctData[i].accountId,acctData[i].checkNumber,acctData[i].date,acctData[i].amount);
}
//Closes File
fclose(fp);
//End Input
//Parameter Receiving:
int pipes[4]; //Pipe Array
int value = 7;
int test;
//Build the pipes
pipes[0] = atoi(argv[1]); //P1_Read
pipes[1] = atoi(argv[2]); //P2_Write
pipes[2] = atoi(argv[3]); //P2_Read
pipes[3] = atoi(argv[4]); //P1_Write
//Troubleshooting
printf("The number of parameters: %d\n",argc);
printf("Parameter 1: %s\n", argv[0]);
printf("I stared correctly\n");
//Testing
close(pipes[0]);
close(pipes[3]);
//SHOULD RECEIVE VALUE HERE
test = read(pipes[2], &value, sizeof(value));
if (test < 0)
{
perror("DB: Failed to read data from parent");
exit(EXIT_FAILURE);
}
else if (test == 0)
{
//Unexpected
fprintf(stderr, "DB: Read End-Of-File from pipe");
}
else
{
//What did the child receive?
printf("DB: Received Value:(%d)\n", value);
}
close(pipes[2]);
close(pipes[1]);
return 0;
}
One of the things you're doing wrong is snprintfing the value of the various elements in fd before you've assigned any value to them. That's undefined behaviour, and the values you're passing as parameters are totally meaningless (at best).
This strikes me as a very odd way to do things, though. Usually you would just dup2 fds 0 and 1 so that the child's stdin and stdout are redirected to the appropriate pipe fds.
I tried reading from the file "hello.txt" but it doesn't enter the while loop at all. The read function returns 0 on EOF and -1 on error. I'm trying to search for the word in w if it exists in the file or not. I'm reading characters from the file and comparing them to w[].
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
char c;
int i=0;
int bytesread;
int flag=1;
char w[]={'h','e','l','l','o'};
if((fd=open("hello.txt",O_RDONLY,0))!=-1){ //if 1
bytesread = read(fd,&c,0);
if(bytesread!=-1){ //if 2
while(bytesread!=0)
{ //while
if(c==w[i])
{ //if 3
i++;
flag=0;
} //end of f3
else if(flag==0&&i!=0)
{ // else 3
i=0;
flag=1;
} // end of else 3
bytesread = read(fd,&c,0);
} //end of while
}else //end of if 2
printf("couldn't read file.\n");
}else //end of if 1
printf("Couldn't open file for read.\n");
} //end of main
ssize_t read(int fd, void *buf, size_t count);
read reads count bytes from the file. You're asking it to read zero bytes when doing bytesread = read(fd,&c,0);. Change it to bytesread = read(fd,&c,1);
Try this:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd;
char c;
int bytesread;
if ((fd = open("hello.txt", O_RDONLY, 0)) != -1) {
while ((bytesread = read(fd, &c, 1)) == 1)
printf("read %d bytes [%c]\n", bytesread, c);
} else
printf("Couldn't open file for read.\n");
return 0;
}
read(fd,&c,0) asks the system to read zero bytes, and it shouldn't be what you want to do.
You should ask the system to read one byte by read(fd,&c,1).
I can't get this basic communication to work.
All I want to do, is send information via the child's stdout to the parents file descriptor.
I am getting a seg fault.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define READ 0
#define WRITE 1
int main(void){
int fdRead[2];
int pid, i, num;
FILE* output;
char mystring [100];
char c;
pid = fork();
if(pid){
FILE * read;
close(fdRead[WRITE]);
read = fdopen(fdRead[READ], "r");
fgets(mystring,100, read);
printf("parent %d",mystring );
} else {
/* child */
dup2(fdRead[WRITE], STDOUT_FILENO);
close(fdRead[READ]);
close(fdRead[WRITE]);
printf("child" );
}
exit(0);
}
Your code does nothing about pipe.
Code for communicating between parent and child processes using pipe looks as follows
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define READ 0
#define WRITE 1
int main(void){
int pipefd[2];
pid_t pid;
int i, num;
if (pipe(pipefd)<0) { /* create pipe */
perror("pipe");
exit(-1);
}
char mystring [100];
char c;
pid = fork();
if(pid<0){
perror("fork");
exit(-1);
} else if (pid=1) { /* parent */
char *mystring = "message to child";
write(pipefd[WRITE],mystring,strlen(mystring);
sleep(1); /* wait for child read message */
char buf[128]; /* buffer to receive data from child */
read(pipefd[READ],buf, sizeof buf);
close(pipefd[READ]);
close(pipefd[WRITE]);
printf("Returned from child %s",buf );
return 0;
} else { /* child */
char *s="send from child: ";
char buf[128];
read(pipefd[READ],buf, sizeof buf);
write(pipefd[WRITE],s,strlen(s));
close(pipefd[READ]);
close(pipefd[WRITE]);
return 0;
}
}
I have a program that takes two files as an argument. The first file is to be copied into the second. The program forks into 2 children, the first child reads file and throws it thru the pipe to the other, then the other child writes it out to a file. The two files are supposed to be identical in the end.
When I run diff to compare the two files I get the following error:
virtual#ubuntu:~/Documents/OSprojects$ ./parent test.txt test2.txt
virtual#ubuntu:~/Documents/OSprojects$ cat test.txt
123456789112233445566778899
virtual#ubuntu:~/Documents/OSprojects$ cat test2.txt
123456789112233445566778899
virtual#ubuntu:~/Documents/OSprojects$ diff test.txt test2.txt
Binary files test.txt and test2.txt differ
virtual#ubuntu:~/Documents/OSprojects$
As you can see they are both the same, but the diff prints out that they are different. Obviously its just something I don't understand about the diff cmd. Any help would be appreciated.
I believe for some reason the file I create is a binary file whereas the first file is not, but I am unaware as to why it is a binary file. I believe it might have to do with this line of code:
write(1, buf, BUF_SIZE); //write to buffer
memset(buf, '\0', BUF_SIZE);
In one of the children this is writing out to the buffer then I am clearing the buffer. Am I clearing out that buffer wrong?
Here is the result of cat -e:
virtual#ubuntu:~/Documents/OSprojects$ cat -e test2.txt
123456789112233445566778899$
^#^#^#^#virtual#ubuntu:~/Documents/OSprojects$
Here is the result of cmp:
virtual#ubuntu:~/Documents/OSprojects$ cmp test.txt test2.txt
cmp: EOF on test.txt
virtual#ubuntu:~/Documents/OSprojects$
I believe that is my problem, how can I clear out that buffer so it doesn't throw those at the end?
ALL OF MY CODE::
Parent:
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUF_SIZE 16
void exitWithError(char* errorMsg, int exitWith); //generic error out function
void launch_writer(const char* pathname, char* const argv[], int pfd[]);
void launch_reader(const char* pathname, char* const argv[], int pfd[]);
int main(int argc, char* argv[]){
//making the pipe
int pfd[2];
if(pipe(pfd) == -1) //test pipe creation
exitWithError("PIPE FAILED", 1);
//forking
pid_t reader_child_pid;
pid_t writer_child_pid;
//args for each fork
char *args_1[] = {"reader", argv[1], (char *) 0};
char *args_2[] = {"writer", argv[2], (char *) 0};
if((writer_child_pid = fork()) == -1) {
exitWithError("WRITER FORK FAILED", 1);
}
else if (writer_child_pid == 0) { //first child comes here
launch_writer("./writer", args_2, pfd);
}
else if ((reader_child_pid = fork()) == -1) {
exitWithError("READER FORK FAILED", 1);
}
else if (reader_child_pid == 0) { //second child comes here
launch_reader("./reader", args_1, pfd);
}
//parent picks up here
//close off pipe from parents end
close(pfd[0]);
close(pfd[1]);
//wait for all processes to exit before ending
for(;;) {
if(wait(NULL) == -1){
if(errno == ECHILD)
exit(0);
else {
exitWithError("WAIT ERROR", 1);
}
}
}
}
void exitWithError(char* errorMsg, int exitWith) {
perror(errorMsg);
exit(exitWith);
}
void launch_writer(const char* pathname, char* const argv[], int pfd[]) {
dup2(pfd[0], 0);
close(pfd[1]);
close(pfd[0]);
execve(pathname, argv, NULL);
perror("execve failed");
}
void launch_reader(const char* pathname, char* const argv[], int pfd[]) {
dup2(pfd[1], 1);
close(pfd[1]);
close(pfd[0]);
execve(pathname, argv, NULL);
perror("execve failed");
}
Child 1:
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 16
int main(int argc, char* argv[]){
//Opens file to be read from
int inFile = open(argv[1], O_RDONLY);
//declaring variables
char buf[BUF_SIZE]; //temp hold whats read/written
int read_test; //check if EOF
for(;;) {
read_test = read(inFile, buf, BUF_SIZE); //read from file
if(read_test == 0) //eof
break;
write(1, buf, BUF_SIZE); //write to buffer
memset(buf, '\0', BUF_SIZE);
}
close(inFile);
exit(0);
}
Child 2:
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define BUF_SIZE 16
int main(int argc, char* argv[]){
//Opens a file for reading/writing, if exists then truncates, otherwise makes new one
//with correct permissions
int wri_inFile = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC , S_IRUSR | S_IWUSR);
if(wri_inFile == -1)
perror("ERROR OPENING FILE");
//declaring variables
char buf[BUF_SIZE]; //to store what is read in/written out
int read_test; //test if EOF
for(;;) {
read_test = read(0, buf, BUF_SIZE); //read from buffer
if(read_test == 0) //eof
break;
write(wri_inFile, buf, BUF_SIZE); //write to file
}
close(wri_inFile);
exit(0);
}
You don't check (and use) the read data length. Therefore, your data gets padded with garbage.
There should be actual data bytes read (read_test):
read_test = read(0, buf, BUF_SIZE); //read from buffer
if(read_test == 0) //eof
break;
write(wri_inFile, buf, BUF_SIZE); //write to file
-----------------------^^^^^^^^
The same applies to the other child. You should also check the error conditions.