How can I generate three child processes respecting a particular order? - c

I'm assigned to make a program that creates three child processes as follows: A, B and C.
Process A reads data from a file and sends 4KB-long fragments to a message queue.
Process B reads these fragments from the queue, converts them and writes the
new data on the queue.
Finally, process C reads the converted string from the message queue and writes it on another file.
I used the fork() function to create them, and I'm having trouble generating the three child processes in a sequential order. When I run the program, usually processes B or C are created before A, and they can't read properly from the message queue because process A hasn't been generated yet.
How could I solve this problem?
This is the code I've been working on:
(Note: Two parameters must be added before running the program: ./program.exe source.txt destination.txt)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <unistd.h>
#define TAM 4096
#define FILEKEY "/bin/cat"
#define KEY 4242
#define N_PROCESSES 3
typedef struct msgbuf{
long type;
char text[TAM];
}message;
int main (int argc, char *argv[]){
key_t key;
pid_t pid;
int msqid;
message env, enda, endb;
message rcv;
message conv;
message msg;
int buf_length;
FILE *f1=NULL;
FILE *f2=NULL;
char string[TAM], *receive;
int rc;
int i;
int status;
int p;
if(argc < 2){
printf("Incorrect command line arguments");
exit(-1);
}
p = getpid();
/*Opens files*/
f1 = fopen(argv[1], "r");
if(f1 == NULL){
exit(-1);
}
f2 = fopen(argv[2], "w");
if(f2 == NULL){
fclose(f1);
exit(-1);
}
/*Obtains key for message queue*/
key = ftok(FILEKEY, KEY);
if(key == -1){
fclose(f1);
fclose(f2);
exit(-1);
}
/*Creates message queue*/
msqid = msgget(key, IPC_CREAT | 0600);
if(msqid == -1){
fclose(f1);
fclose(f2);
exit(-1);
}
/*Message types*/
env.type = 1; /*Message from process A to process B*/
enda.type = 2; /*Process A has finished reading data from f1*/
conv.type = 3; /*Message from process B to process C*/
endb.type = 4; /*Process B has finished converting the string*/
/*Message size (4KB)*/
buf_length = sizeof(message)-sizeof(long);
/*Creates processes A, B and C*/
for ( i = 0; i < N_PROCESSES; i++){
pid = fork();
if(pid == -1){ /*Error*/
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
exit(-1);
}else if (pid == 0 && i == 0){/*Process A*/
/*Reads from f1 while end of file is not reached*/
while (fgets(string, TAM, f1) !=NULL){
/*Copies string to env.text*/
strcpy(env.text, cadena);
/*Sends text fragments (4KB) to message queue*/
if(msgsnd(msqid, &env, buf_length, IPC_NOWAIT)<0){
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
exit(-1);
}
}
/*Process A sends this message when there's no more data to read*/
if(msgsnd(msqid, &enda, buf_length, IPC_NOWAIT)<0){
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
exit(-1);
}
exit(EXIT_SUCCESS);
}else if(pid == 0 && i == 1){/*Process B*/
/*Reads text fragments (4KB) from message queue*/
while (msgrcv(msqid, &rcv, buf_length, 1, IPC_NOWAIT)>0) {
/*Converts string*/
strcpy(receive, rcv.text);
for(i = 0; i < TAM; i++){
receive[i] = toupper(receive[i]);
}
strcpy(conv.text, receive);
/*Sends fragments of converted string to message queue*/
if(msgsnd(msqid, &conv, buf_length, IPC_NOWAIT)<0){
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
exit(-1);
}
}
/*The loop finishes when there's an error or when there are no more type 1 messages to read*/
/*Reads type 2 message from process A*/
rc = msgrcv(msqid, &rcv, buf_length, 2, 0);
if( rc == -1){
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
exit(-1);
}
/*Process B sends this message indicating that it has finished sending string fragments*/
if(msgsnd(msqid, &endb, buf_length, IPC_NOWAIT)<0){
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
exit(-1);
}
exit(EXIT_SUCCESS);
}else if(pid == 0 && i == 2){/*Process C*/
/*Reads converted string fragments from message queue*/
while (msgrcv(msqid, &msg, buf_length, 3, IPC_NOWAIT)>0) {
/*Writes fragments on another file*/
if(fputs(msg.text, f2)<0){
exit(-1);
}
}
/*The loop finishes when there are no more fragments to write on f2*/
/*Then process C reads the last message sent from B*/
rc = msgrcv(msqid, &rcv, buf_length, 4, 0);
if( rc == -1){
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
exit(-1);
}
exit (EXIT_SUCCESS);
}
}
/*Parent process waits for processes A, B and C*/
for (i=0; i<N_PROCESSES; i++) {
pid=wait(&status);
printf("Process %d with PPID = %d terminated\n", pid, p);
}
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
return (EXIT_SUCCESS);
}

The processes are created in the order you specified, but the scheduler can schedule them in any order it likes, so you find code from process B executing before process A has finished, etc.
What I'd do to set up the situation you want is have 2 queues, one from A to B, the other from B to C. I'd create them all in the parent, to keep things simple.
Then I'd have the reading children do blocking reads (msgrcv() without IPC_NOWAIT), or I'd loop until I got a failure other than no data received.
The sending processes (A and B) would both put "and that's all" indicators into the queue when done, so the receivers would know they had everything.

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");
}
}

Issue read write file using pipe fork shared memory

I am trying to use pipes in C. I have two create two pipes between parent and child process.I have to read a file in chunks of 4096 bytes (or smaller if there is less) and I have to send through the pipes the amount of data that was read and how many times there have been readings. For example, to copy a 6KB file, the parent writes the first 4KB data of the file to the shared memory and send two integers, 1 and 4096, to the child via the pipe. The child receives these two numbers, copies 4096 bytes from the shared memory to the output file, and sends back 1 to the parent via the other pipe. After receiving 1, the parent copies the left 2KB data to the shared memory and send 2 and 2048 to the child. The child receives them from the pipe, copies 2048 bytes to the output file, and replies with 2 to the parent. The parent then send 0, 0 to the child. The child receives 0 and replies with a 0 and then exit. The parent receives 0 and exits too.
Currently my program works for file less than one block but not for file greater then one block (4096 bytes)
697, thank you for pointing out, I have modified my program as following but still has issues, basically how to control the flow as parent-child-parent-child ...
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define SIZE 4096
int file_exist (char *filename)
{
struct stat buffer;
return (stat (filename, &buffer) == 0);
}
int main(int argv, char *argc[]) {
/*Check if program is called correctly*/
if(argv != 3) {
printf("Please call program appropriately\n");
exit(EXIT_FAILURE);
}
FILE *r, *w;
void *sharedMem;
int datapipe[2];
int blockpipe[2];
int shm;
char userInput[5];
char *name = "fsuid_cop4610";
if (file_exist (argc[2]))
{
printf("Would you like to overwrite file (yes/no): ");
scanf("%s", userInput);
if(!strcmp(userInput, "yes")) {
printf("Overwriting file...\n");
//fclose(w);
w = fopen(argc[2], "wb");
if(w == NULL) {
perror("Error with write file");
exit(EXIT_FAILURE);
}
}
else if(!strcmp(userInput, "no")) {
printf("Will not overwrite\n");
exit(EXIT_FAILURE);
}
else {
printf("User input not accepted\n");
exit(EXIT_FAILURE);
}
}
/*Check if read file can open*/
r = fopen(argc[1], "rb");
if(r == NULL) {
perror("Error opening read file");
exit(EXIT_FAILURE);
}
fseek(r, 0, SEEK_END); // seek to end of file
int inputlength = ftell(r); // get current file pointer
printf("inputlength is %d\n",inputlength);
int numofblock = inputlength/SIZE + 1;
fseek(r, 0, SEEK_SET); // seek back to beginning of file
/*Check if write file can open*/
if (pipe(datapipe) < 0) {
perror("Pipe");
exit(EXIT_FAILURE);
}
if (pipe(blockpipe) < 0) {
perror("Pipe");
exit(EXIT_FAILURE);
}
/*Check if forking process is successful*/
pid_t pid = fork();
if(pid < 0) {
perror("Fork");
exit(EXIT_FAILURE);
}
shm = shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if(shm == -1) {
perror("Shared memory");
exit(EXIT_FAILURE);
}
if(ftruncate(shm, SIZE) == -1) {
perror("Shared Memory");
exit(EXIT_FAILURE);
}
sharedMem = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
if(sharedMem == MAP_FAILED) {
perror("Mapping shared memory");
exit(EXIT_FAILURE);
}
if (pid>0) { // parent
printf(" parent before close data0,block1\n");
close(datapipe[0]); // close read, will write data
close(blockpipe[1]); // close write, will read block number
printf(" parent close data0,block1\n");
for (int i=1; i<=numofblock; i++)
{
printf("... parent process\n");
int blocknumber=i;
printf("parent read from input file into shared memory\n");
int P2SHM = fread(sharedMem, 1, SIZE, r);
if(P2SHM < 0) {
perror("Could not store to shared memory");
exit(EXIT_FAILURE);
}
//printf("parent shared memory conent: %s\n",(char *)sharedMem);
printf("parent data read %d\n",P2SHM);
if (i==1)
{
printf("i=%d parent write to data pipe\n",i);
if(write(datapipe[1], &P2SHM, sizeof(int)) < 0) {
perror("parent failed to write to pipe bytes");
exit(EXIT_FAILURE);
}
if(write(datapipe[1], &blocknumber, sizeof(int)) < 0) {
perror("parent failed to write to pipe block number");
exit(EXIT_FAILURE);
}
}
printf("parent read from block pipe\n");
int C2P = read(blockpipe[0], &blocknumber, sizeof(int));
if(C2P < 0) {
perror("parent failed to read value from blockpipe");
exit(EXIT_FAILURE);
}
/*else if(C2P == 0) {
printf("End of file reached\n");
}*/
else {
printf("parent block %d Received succesfully\n", blocknumber);
if (i>= 2)
{
printf("i=%d parent write to data pipe\n",i);
//close(datapipe[0]); // close read, will write data
if(write(datapipe[1], &P2SHM, sizeof(int)) < 0) {
perror("parent failed to write to pipe bytes");
exit(EXIT_FAILURE);
}
if(write(datapipe[1], &blocknumber, sizeof(int)) < 0) {
perror("parent failed to write to pipe block number");
exit(EXIT_FAILURE);
}
//close(datapipe[1]);
}
if(C2P == 0) {
printf("parent End of file reached\n");
}
}
} // end for
printf(" parent before close data1,block0\n");
close(datapipe[1]);
close(blockpipe[0]);
printf(" parent close data1,block0\n");
printf(" ... existing parent process\n");
}
else { // pid=0 child
printf(" child before close data1,block0\n");
close(datapipe[1]); // close write, will read data
close(blockpipe[0]); // close read, will write block number
printf(" child close data1,block0\n");
for (int j=1; j<=numofblock; j++)
{
printf(".... child process\n");
int cBytes, len, len2;
int blocknumber = 1;
printf("child read from datapipe\n");
len = read(datapipe[0], &cBytes, sizeof(cBytes));
len2 = read(datapipe[0], &blocknumber, sizeof(blocknumber));
printf("child wrote to blockpipe blocknumber=%d\n", blocknumber);
write(blockpipe[1], &blocknumber, sizeof(blocknumber));
printf("child There are %i bytes\n", cBytes);
if(len >= 0)
{
printf("child writing to file\n");
//fwrite(sharedMem, 1, sizeof(sharedMem), w);
//printf("child shared memory conent: %s\n",(char *)sharedMem);
char* res = (char *)sharedMem;
//printf("res = %s\n",res);
//printf("errno before write=%d",errno);
shm_unlink(name);
//int writtenbyte = fwrite(res, sizeof(char), strlen(res), w);
int writtenbyte = fwrite(res, sizeof(char), cBytes, w);
if(errno == EINTR) {
printf("somewhting wrong");
}
//printf("errno after write=%d",errno);
printf("writtenbyte = %d\n",writtenbyte);
//fclose(w);
//fputs((char *)sharedMem, w);
//fwrite(s->name, sizeof(char), strlen(s->name) + 1, fp);
}
/*else if (len == 0) {
printf("End of fle reached\n");
}*/
else { // len < 0
perror("Failed to read from pipe");
exit(EXIT_FAILURE);
}
} // after for
printf(" child before close data0,block1\n");
close(datapipe[0]);
close(blockpipe[1]);
printf(" child close data0,block1\n");
printf("... exiting Child process\n");
}
//shm_unlink(name);
//fclose(r);
fclose(w);
return 0;
}
Result:
inputlength is 4177
parent before close data0,block1
parent close data0,block1
... parent process
parent read from input file into shared memory
parent data read 4096
i=1 parent write to data pipe
parent read from block pipe
child before close data1,block0
child close data1,block0
.... child process
child read from datapipe
child wrote to blockpipe blocknumber=1
child There are 4096 bytes
child writing to file
parent block 1 Received succesfully
... parent process
parent read from input file into shared memory
parent data read 81
parent read from block pipe
parent block 2 Received succesfully
i=2 parent write to data pipe
Note child write block number 1, but parent received block number 1, then received block number 2, and after the 2nd write from parent it stopped, without writing output file. Any thoughts for that?

Connection between group of daemons and main process - mkfifo

I was trying to connect daemons (group of daemons without a leader) with main process as in title, the problem is that i have to send statement from each daemon(which are supporting SIGUSR1 signal) to main process, but i don' t even know how to do that, in my code i used mkfifo, but it's not working at all..
here is the main process source:
int main(int argc, char* argv[])
{
pid_t pid;
int i;
int n = atoi(argv[1]);
char c, message[255];
if(argc!=2){
printf("please insert one parametr\n");
return -1;
}
int fd = open("pipe", O_RDONLY);
if (fd == -1) {
perror("Failed open fifo to read");
return EXIT_FAILURE;
}
for( i = 0; i < n; i++) {
pid=fork();
if (pid==0){
printf("daemon created..\n");
}
else{
execl("daemons", "daemons", argv[1], NULL);
while(1){
sleep(2);
read(fd, message, c);
printf("P received: %s\n", message);
close(fd);
//read(fd[0], message, sizeof(message));
}
}
}
return 0;
}
and here is some source code in which i create daemons:
int fd = open("pipe", O_WRONLY);
if (fd < 0){
perror("cannot open fifo: ");
return EXIT_FAILURE;
}
if ( getppid() == 1 )
return 0;
/* Creating daemon */
pid[n] = fork();
if (pid[n] < 0)
exit(EXIT_FAILURE);
if (pid[n] > 0)
exit(EXIT_SUCCESS);
/* Setting leader of session */
sid = setsid();
if (sid < 0){
exit(EXIT_FAILURE);
}
/* fork one more time to make children
to have an opportunity to destroy
session leader */
for ( i = 0; i < n; i++){
pid[i] = fork();
if(pid[i] < 0){
printf("filed to fork...\n");
exit(EXIT_FAILURE);
}
if(pid[i]==0){
while(1){
sleep(2);
printf("Demon[%d]: My ID in pipe.%d\n", i+1, getpid());
signal(SIGUSR1, sigHandler);
write(fd, "Hi\n", strlen("Hi\n"));
close(fd);
}
}
chdir(".");
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
file = fopen("log_file.txt", "w+");
fclose(file);
umask(027);
}
at least i' m not sure about that i am creating daemons in good way..
And where i should put signal, which can be later executed?
Do you have any suggestions?

Problems with shared buffer and synchronized programming

I just started learning how to mess with threads and synchronized programming in C. I'm trying to code a reader which uses threads (POSIX interface) to read selected files from a shared buffer. The children threads will retrieve the file names from the buffer, while the father thread will be infinitly reading filenames from stdin and placing them in the buffer. What am I doing wrong?
pthread_mutex_t lock;
static char* files[NFILES];
int top = NFILES-1;
void putInBuffer(char* file){
pthread_mutex_lock(&lock);
if(top < NFILES-1){
files[top] = file;
top++;
}
pthread_mutex_unlock(&lock);
}
char* removeFromBuffer(){
char* file;
pthread_mutex_lock(&lock);
file = files[top];
top--;
pthread_mutex_unlock(&lock);
return file;
}
void* leitor(){
int op,i,r,cl;
char* file;
char buff[NCHARS];
char teste[NCHARS];
while(1){
pthread_mutex_lock(&lock);
file = removeFromBuffer();
printf("%s\n", file);
op = open(file, O_RDONLY);
if(op == -1) {
perror("Open unsuccessful");
pthread_exit((void*)-1);
}
r = read(op, teste, NBYTES);
if(r == -1){
perror("Read unsuccessful");
pthread_exit((void*)-1);
}
for(i=0; i<NLINES-1; i++){
r = read(op, buff, NBYTES);
if(r == -1){
perror("Read unsuccessful");
pthread_exit((void*)-1);
}
if(strcmp(buff,teste) != 0){
perror("Incorrect file");
pthread_exit((void*)-1);
}
}
cl = close (op);
if(cl == -1){
perror("Close unsuccessful");
pthread_exit((void*)-1);
}
printf("Correct file: %s\n", file);
pthread_mutex_unlock(&lock);
}
pthread_exit((void*)0);
return NULL;
}
int main(){
pthread_t threads[NTHREADS];
int i,*status;
char file[LENFILENAME];
if (pthread_mutex_init(&lock, NULL))
{
perror("\n mutex init failed\n");
exit(-1);
}
for(i=0;i<NTHREADS;i++){
if(pthread_create(&(threads[i]),NULL, leitor,NULL)){
perror("Failed to create thread");
exit(-1);
}
}
while(1){
read(STDIN_FILENO, file, LENFILENAME);
printf("%s\n", file);
putInBuffer(file);
printf("%s\n", removeFromBuffer());
}
for (i=0;i<NTHREADS;i++){
if(pthread_join(threads[i],(void**)&status)){
perror("Failed to join thread");
exit(-1);
}
printf("Thread returned %d\n", status);
}
pthread_mutex_destroy(&lock);
return 0;
}
Given what your program is doing, it seems that you should use a separate semaphore for notifying the child threads of new input instead of using the mutex that you have created.
Each child thread should wait on the semaphore at the top of the while loop, where you currently have pthread_mutex_lock(). After the parent has finished putInBuffer, it should release the semaphore once. When a child thread grabs the semaphore, it can call removeFromBuffer to get the next file, and read it (i.e. what you have already written). After the child finishes with the file, it should not release the semaphore, just go back to the top of the loop and wait on it again.
You have correctly used the mutex in putInBuffer and removeFromBuffer to protect accesses to the shared variables files and top.

Pipe to and from child process is not working

I am trying to learn pipes and I am trying out this program:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<fcntl.h>
#define MAXLINE 100
void main(){
int pipe1[2],pipe2[2];
pid_t childpid;
if(pipe(pipe1)<0){
perror("Unable to create the pipe for pipe1");
exit(-1);
}
if(pipe(pipe2)<0){
perror("Unable to create the pipe for pipe1");
exit(-1);
}
childpid=fork();
printf("The child PID is:%d\n",childpid);
if(childpid==0){
printf("In the child process");
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0],pipe2[1]);
exit(0);
}
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0],pipe1[1]);
waitpid(childpid,NULL,0);
exit(0);
}
void client(int readfd,int writefd){
int n,len;
char buff[MAXLINE];
printf("Please enter the name of the file to be read:");
fgets(buff,MAXLINE,stdin);
len=strlen(buff);
if(buff[len-1]=='\n')
len--;
write(writefd,buff,len);
printf("File name written into the pipe\n");
printf("The num of bytes written are:\n",read(readfd,buff,MAXLINE));
while((n-read(readfd,buff,MAXLINE))>0){
printf("Trying to read the content\n");
write(STDOUT_FILENO,buff,n);
}
}
void server(int readfd,int writefd){
int fd,n;
char buff[MAXLINE + 1];
write(writefd,"Yello in the server process",strlen("Yello in the server process"));
if((n=read(readfd,buff,MAXLINE))==0)
perror("End of file while reading");
buff[n]='\0';
if((fd=fopen(buff,O_RDONLY))<0){
snprintf(buff+n,sizeof(buff)-n,"Can't open, %s",strerror(errno));
n=strlen(buff);
write(writefd,buff,n);
}
while( (n=read(fd,buff,MAXLINE))>0){
write(writefd,buff,n);
close(fd);
}
}
The problem is I enter the file name and the program just exits. I tried to gdb the child process by setting set "follow-fork-mode child", and still nothing happens. Any ideas as to where I could be going wrong?
Ok, some more additional debugging info is: I set the follow-fork-mode to child.and it is causing a segmentation fault at the opening of the file.
Program received signal SIGSEGV, Segmentation fault.
[Switching to process 28025]
0x00197f08 in _IO_file_fopen () from /lib/libc.so.6
This code in client() looks suspicious:
while((n-read(readfd,buff,MAXLINE))>0){
Surely, that should be:
while ((n = read(readfd, buff, MAXLINE)) > 0)
{
The change from - to = is the important one, of course; the rest are cosmetic (and one is even controversial).
You should also pay attention to compiler warnings. Given:
int fd,n;
...
if((fd=fopen(buff,O_RDONLY))<0){
There's no way this should be compiling without major warnings; fopen() returns a FILE *, not a file descriptor (int).
You also seem to have some odd communications. The server sends a message to the client before reading the file name from the client. The client, OTOH, does not necessarily read that message separately; it gets a glob of information and reports how many bytes it got. That may have included some of the file as well as the introductory message.
You shouldn't close a file in the loop that is reading from it:
while( (n=read(fd,buff,MAXLINE))>0){
write(writefd,buff,n);
close(fd);
}
The close should be outside the loop.
This code more or less works; it is messier than I'd like, but it does more or less work.
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXLINE 100
static void server(int readfd, int writefd);
static void client(int readfd, int writefd);
int main(void)
{
int pipe1[2], pipe2[2];
pid_t childpid;
if (pipe(pipe1)<0)
{
perror("Unable to create the pipe for pipe1");
exit(-1);
}
if (pipe(pipe2)<0)
{
perror("Unable to create the pipe for pipe2");
exit(-1);
}
childpid = fork();
printf("The child PID is:%d\n", childpid);
if (childpid == 0)
{
printf("In the child process\n");
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0], pipe2[1]);
exit(0);
}
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0], pipe1[1]);
waitpid(childpid, NULL, 0);
return 0;
}
static void client(int readfd, int writefd)
{
int n, len;
char buff[MAXLINE];
printf("Please enter the name of the file to be read:");
fgets(buff, MAXLINE, stdin);
len = strlen(buff);
if (buff[len-1]=='\n')
len--;
write(writefd, buff, len);
printf("File name (%.*s) written into the pipe\n", len, buff);
printf("The num of bytes written are: %d\n", (int)read(readfd, buff, MAXLINE));
while ((n = read(readfd, buff, MAXLINE)) > 0)
{
printf("Trying to read the content\n");
write(STDOUT_FILENO, buff, n);
}
}
static void server(int readfd, int writefd)
{
int fd, n;
char buff[MAXLINE + 1];
fprintf(stderr, "Server: %d\n", (int)getpid());
write(writefd, "Yello in the server process", strlen("Yello in the server process"));
if ((n = read(readfd, buff, MAXLINE))==0)
perror("End of file while reading");
buff[n] = '\0';
if ((fd = open(buff, O_RDONLY)) < 0)
{
snprintf(buff+n, sizeof(buff)-n, "Can't open, %s", strerror(errno));
n = strlen(buff);
write(writefd, buff, n);
}
else
{
while ((n = read(fd, buff, MAXLINE)) > 0)
{
if (write(writefd, buff, n) != n)
{
fprintf(stderr, "Write failed in server\n");
break;
}
}
close(fd);
}
}
Note that the code does not try using a file descriptor that it fails to open. It does not crash; the n-read(...) problem is one major part of the trouble, comments notwithstanding. The misuse of fopen() for open() was another major part of the trouble.

Resources