The task is this: there is a parent process - a server, and several client-children. It is necessary that the client sends the message to the server through the pipes, and the server sends it to the other clients.

#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> struct client{ int fd[2]; pid_t pid; }; int main(){ fd_set read_set; struct client clients[2]; struct client servers[2]; struct timeval tv; tv.tv_sec = 2; tv.tv_usec = 0; int i = 0; int j = 0; int k = 0; int r = 0; int serverbytes; int clientbytes; char serverbuffer[80]; char clientbuffer[80]; char message[80]; for(r;r<2;r++) { if(pipe(clients[r].fd) < 0) printf("pipe %i error \n", r); else printf("client pipe %i created \n", r); } r = 0; for(r;r<2;r++) { if(pipe(servers[r].fd) < 0) printf("pipe %i error \n", r); else printf("server pipe %i created \n", r); } clients[0].pid = fork(); if(clients[0].pid != 0) { clients[1].pid = fork(); if(clients[1].pid != 0){ printf("server works. pid=%i \n", getpid()); while(1){ int maxfd = clients[1].fd[0]; FD_ZERO(&read_set); FD_SET(clients[0].fd[0], &read_set); FD_SET(clients[1].fd[0], &read_set); int serverSelect = select(maxfd+1, &read_set, NULL, NULL, &tv); if(serverSelect != -1){ for(k;k<2;k++) { if(FD_ISSET(clients[k].fd[0], &read_set)){ serverbytes = read(clients[k].fd[0], serverbuffer, sizeof(serverbuffer)); printf("server receive: %s from client ID=%d \n", serverbuffer, k); for(i;i<2;i++){ if(i!=k){ close(servers[k].fd[0]); write(servers[k].fd[1], serverbuffer, sizeof(serverbuffer)); } } } } } else if(serverSelect == 0) printf("select timeout \n"); else perror("err"); sleep(5); } } else { sprintf(message,"child %d", 1); printf("client %i works. pid=%i \n", 1, getpid()); //close(servers[1].fd[1]); //open(servers[1].fd[0]); //if(read(servers[1].fd[0], clientbuffer, sizeof(clientbuffer)) == -1){ //printf("client %i read error \n",1); //} //else //printf("client %i receive %s \n",1,clientbuffer); //close(clients[1].fd[0]); while(1){ write(clients[1].fd[1], message, (strlen(message)+1)); printf("client %i send: %s \n", 1, message); sleep(3); } exit(0); } } else { sprintf(message,"child %d", 0); printf("client %i works. pid=%i \n", 0, getpid()); //close(servers[0].fd[1]); //open(servers[0].fd[0]); //if(read(servers[0].fd[0], clientbuffer, sizeof(clientbuffer)) == -1){ //printf("client %i read error \n",1); //} //else //printf("client %i receive %s \n",1,clientbuffer); //close(clients[0].fd[0]); while(1){ write(clients[0].fd[1], message, (strlen(message)+1)); printf("client %i send: %s \n", 0, message); sleep(3); } exit(0); } return 0; } 

I make for each client two paypas - for sending to the server and for receiving from the server. The problem is that the server does not execute select c errno = 2 (no such file or directory). Why such a mistake? Thank you in advance.

UPD: after changes from @avp and wrapping processes into infinite loops (the program itself is some kind of chat chatting) the output of the program:

 client pipe 0 created client pipe 1 created server pipe 0 created server pipe 1 created client 0 works. pid=32663 client 1 works. pid=32664 client 0 send: child 0 client 1 send: child 1 server works. pid=32662 server receive: child 0 from client ID=0 server receive: child 1 from client ID=1 client 0 send: child 0 client 1 send: child 1 client 0 send: child 0 client 1 send: child 1 client 1 send: child 1 client 0 send: child 0 client 1 send: child 1 client 0 send: child 0 client 1 send: child 1 client 0 send: child 0 

That is, the server receives once messages from the client, and after that they spin. Why only once?

Child processes should also receive redirected messages from the server, everything is written for this, but I had to be commented out, because otherwise even the basis does not work ... I understand that the question is most likely stupid, but I am only learning to write under the rules.

  • one
    And what could this call mean? open (servers [1] .fd [0]); And further. It's cool to see for (r; r <2; r ++) (is this some kind of secret ritual?) - alexlz
  • I can say for the first time I work with C under the Nicks ... so, yes, cool. and about for did not understand. open'om I tried to rediscover the handle, but I already understood my mistake - Max Zhukov
  • one
    As for for'a, these lines are identical: for (r; r <2; r ++) for (; r <2; r ++) - alexlz
  • @alexlz, I work on .NET, so for me such a signature is unusual :) - Max Zhukov

1 answer 1

First of all, select returns 0 if it’s timeout (see you have tv ) and this is normal, i.e. errno in select not populated, and you do not check for zero.

And also, it is better to install tv and read_set each time before calling select() , since they can be modified by this challenge.

Correct and see what happens.

When debugging, print more information (getpid (), getppid (), return codes, etc.).

  • @avp, thanks for the reply. I corrected the code according to your comments. now it does not fall out with an error, but it still does not work. output: client pipe 0 created client pipe 1 created server pipe 0 created server pipe 1 created client 0 works. pid = 32533 client 1 works. pid = 32534 client 1 send: child 1 server works. pid = 32532 client 0 send: child 0 - Max Zhukov
  • one
    @Max Zhukov, look at for (k; k <2; k ++) {it is obvious that during the second and all other passes, k will be equal to 2 and the body of the cycle will not be executed. This is an obvious reason that you do not see a reaction to select() . And if (serverSelect! = -1) {....} else if (serverSelect == 0) looks ridiculous (guess yourself). What prevents you from printing the result of a function call (which, by the way, you are studying ) immediately after its call. Then, because you yourself will be easier to understand the behavior of the program. - By the way, it is better to close unnecessary for the process of the pipe in it after the fork - avp
  • @avp, well, for for and if I am ashamed. but: if I uncomment the code in the clients (reading from the pipe to which the server writes after receiving the message just in this for loop) except for the open () function, which is clearly not in the subject here, select () returns 0. therefore, the timeout is . just in case I tried to increase it to 5 seconds, but this is not serious, and the result is the same. The problem, as I understand it, is that the client cannot read from the pipe. This is most likely due to the close () function. Therefore, the question is: how to rediscover the pipe? That is, something like this: open pipe read from pipe close pipe - Max Zhukov
  • 2
    @Max Zhukov, the timeout here may have nothing to do with it, although it should be reinstalled immediately before select() On Linux, select () modifies timeout to reflect the amount of time not slept; Where do you client reads the pipe, I do not see. - Reopen the pipe can not be . The idea is that you need to close only what you need, and the code you have is confused to disgrace, select the client code in one function with the necessary parameters. Here you do the pipe (servers [i] .fd); If you want the server to write to it, and the client read, then after fork () the server should do close (servers [i] .fd [0]), and the client ... fd [1]. - avp
  • @avp, figured out. Thank you so much for accurate answers and patience! - Max Zhukov