Plugs and pipes in C UNIX

I'm not sure that I even bark on the right tree here ... but here it goes.

I am trying to pass data from my parent process to all children. This is a simple server program that basically saves a list of connected clients, and then sends a routing table of connected clients to each client. Ultimately, this will include a structure of information about each client ... but now I just want to get every forked process to get the same information from the parent.

In the parent process, I first configured my pipes and set them to non-blocking (if there is no new data in the pipe). After a connection is established with the client, the number of variable elements increases to reflect this new connection. Then I split the child process into a new function and update the array of arrays with the new number of records in the table (I have 10 pipes at the moment to check if I need to maintain a separate channel for each child).

pid_t pid; int numchildren; int i, n; /* Create the pipes. */ for(i = 0; i < 10; i++) { if (pipe (mypipe[i])) { fprintf (stderr, "Pipe failed.\n"); return EXIT_FAILURE; } } for(i = 0; i < 10; i++) { for(n=0; n<2; n++) { // Get previous flags int f = fcntl(mypipe[i][n], F_GETFL, 0); // Set bit for non-blocking flag f |= O_NONBLOCK; // Change flags on fd fcntl(mypipe[i][n], F_SETFL, f); } //close(mypipe[i][0]); } pid = fork(); if (pid == (pid_t) 0) { close (mypipe[numentries-1][1]); recievecmds(new_fd, mypipe[numentries-1][0]); close(new_fd); return EXIT_SUCCESS; } else if (pid < (pid_t) 0) { fprintf (stderr, "Fork failed.\n"); return EXIT_FAILURE; } else { sprintf (buf,"%d",numentries); for(i = 0; i < 10; i++) write(mypipe[i][1], buf, strlen(buf)); memset(&buf, 0, sizeof buf); } 

And then I try to read Whats in the pipe in the recievecmds () function:

 nbytes = read(mypipe[childindex][0], buf, sizeof(buf)); 

The first connected client tells me numentries = 1, the second client tells me numentries = 2, and so on. I mean, I don’t even see the point in the pipe, because it seems that everything I put into the pipe can simply transfer it to the function that I called on the plug. Am I really wrong? It was very unpleasant, trying to figure it out. How can I control all my child processes from my parent process at the same time?

Thank you so much in advance.

edit - My main problem was that I updated the channel every time in an infinite while loop. A very stupid mistake, I immediately realized that this is probably the root of my problem. However, although now the first child / pipe combination contains the correct data ... the second is not. I'll see if I can figure it out on my own, thanks for the tip!

Of course, now I am facing problems, because I manually select the option to output data from the channel. I am going to come up with a way, perhaps either to get data for all pipes every time it is updated, or to get only the latest data (maybe only one char at a time).

Thanks for sharing with me guys! And I apologize for not publishing the whole program ... but there is very little. I definitely should have mentioned that I have this in an infinite loop.

+4
source share
2 answers

Various observations

  • Do not make pipes non-blocking; you want children to lock when there is no data. At least in the early stages of design; later you can let them work when there is no pending data.
  • You need to be careful with your plumbing. A parent needs 10 pipes, one for each child. But he needs only the end of the record, not the end.
  • Each child needs one reading tube. Any extra pipes (for example, the ends of the pipe record that the parent has already opened before the branch of the Nth child) must be closed.
  • You might consider using streams β€” in this case, you could pass the data on to the children. But in the long run, it seems that you will periodically pass the data to the children, and then you need a mechanism to receive the data (except for calling the function).
  • Pipes are "lightweight" if you pay close attention to what file descriptors are used. Close all descriptors that you do not need.
  • The parent will have to go around all ten pipes, writing the same data to each.
  • It will also be necessary to consider what to do if the child leaves. He must close the phone (no longer use) and decide whether to start a new child (but how will he ensure that the new child has all the information he has accumulated?).
  • Beware of SIGPIPE - maybe install a handler or maybe use SIG_IGN and find write errors instead of signals.

Working code

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> enum { NUM_CHILDREN = 10 }; enum { NUM_MESSAGES = 10 }; static int write_pipes[NUM_CHILDREN]; static int n_pipes; static void be_childish(int *pipe) { int i; char buffer[32]; int nbytes; int pid = getpid(); close(pipe[1]); for (i = 0; i < n_pipes; i++) close(write_pipes[i]); printf("Child %d\n", pid); while ((nbytes = read(pipe[0], buffer, sizeof(buffer))) > 0) { printf("Child %d: %d %.*s\n", pid, nbytes, nbytes, buffer); fflush(0); } printf("Child %d: finished\n", pid); exit(0); } int main(void) { pid_t pid; int i, j; /* Create the pipes and the children. */ for (i = 0; i < NUM_CHILDREN; i++) { int new_pipe[2]; if (pipe(new_pipe)) { int errnum = errno; fprintf(stderr, "Pipe failed (%d: %s)\n", errnum, strerror(errnum)); return EXIT_FAILURE; } if ((pid = fork()) < 0) { int errnum = errno; fprintf(stderr, "Fork failed (%d: %s)\n", errnum, strerror(errnum)); return EXIT_FAILURE; } else if (pid == 0) { be_childish(new_pipe); } else { close(new_pipe[0]); write_pipes[n_pipes++] = new_pipe[1]; } } for (i = 0; i < NUM_MESSAGES; i++) { char message[30]; int len; snprintf(message, sizeof(message), "Message %d", i); len = strlen(message); for (j = 0; j < n_pipes; j++) { if (write(write_pipes[j], message, len) != len) { /* Inferior error handling; first failure causes termination */ fprintf(stderr, "Write failed (child %d)\n", j); exit(1); } } sleep(1); } printf("Parent complete\n"); return 0; } 
+6
source

I would suggest using a shared memory segment. Your parent and child processes can mmap the same file and read / write status. This can be an actual file or anonymous memory segment. This is exactly what Apache does with ScoreBoardFile .

+1
source

All Articles