C: «те же файловые дескрипторы всех клиентских подключений» (программирование клиентских серверов)

На каждом новом клиентском соединении процесс вильчатого сервера

разные процессы (другие дочерние серверы, т.е. exec) не могли идентифицировать этого клиента с тем же самым fd при использовании в forked child.

Как я могу отличить клиента от других процессов?

accept call возвращает такое же значение, если дескриптор файла new sockfd

/* server process */ #include  #include  #include  #include  #include  #define SIZE sizeof(struct sockaddr_in) void catcher(int sig); int newsockfd; int main(void) { int sockfd; char c; struct sockaddr_in server = {AF_INET, 7000, INADDR_ANY}; static struct sigaction act; act.sa_handler = catcher; sigfillset(&(act.sa_mask)); sigaction(SIGPIPE, &act, NULL); /* set up the transport end point */ if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket call failed"); exit(1); } /* bind an address to the end point */ if ( bind(sockfd, (struct sockaddr *)&server, SIZE) == -1) { perror("bind call failed"); exit(1); } /* start listening for incoming connections */ if ( listen(sockfd, 5) == -1 ) { perror("listen call failed"); exit(1) ; } for (;;) { /* accept a connection */ if ( (newsockfd = accept(sockfd, NULL, NULL)) == -1) { perror("accept call failed"); continue; } printf("New connection. File descriptor fd is %d\n",newsockfd); /* spawn a child to deal with the connection */ if ( fork() == 0) { while (recv(newsockfd, &c, 1, 0) > 0) { c = toupper(c); send(newsockfd, &c,1, 0); } /* when client is no longer sending information the socket can be closed and the child process terminated */ close(newsockfd); exit (0); } /* parent doesn't need the newsockfd */ close(newsockfd); } } void catcher(int sig) { close(newsockfd); exit (0); } /* client process */ #include  #include  #include #include #include  #include  #define SIZE sizeof(struct sockaddr_in) int main(void) { int sockfd; char c, rc; struct sockaddr_in server = {AF_INET, 7000}; /* convert and store the server's IP address */ server.sin_addr.s_addr = inet_addr("127.0.0.1"); /* set up the transport end point */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket call failed"); exit(1); } /* connect the socket to the server's address */ if ( connect (sockfd, (struct sockaddr *)&server, SIZE) == -1) { perror("connect call failed"); exit(1); } /* send and receive information with the server */ for(rc = '\n';;) { if (rc == '\n') printf("Input a lower case character\n"); c = getchar(); send(sockfd, &c, 1, 0); if (recv(sockfd, &rc, 1, 0) >0) printf("%c", rc); else { printf("server has died\n"); close(sockfd); exit(1); } } } 

Номер дескриптора файла уникален только в том процессе, в котором он существует, и как только он закрыт, его можно повторно использовать (например, в следующий раз, когда вы вызываете accept ). Это не хороший выбор «идентификатора соединения».

В вашем случае, когда у вас есть новый процесс для каждого соединения, самым естественным идентификатором для соединения будет идентификатор процесса, но вы его выбросили, не сохраняя возвращаемое значение fork . В родительском процессе fork возвращает pid дочернего процесса, который он создал. Вы хотите сохранить это и использовать его позже. В частности, вы можете использовать его для уничтожения дочернего процесса или определения того, когда дочерний процесс завершается (функции wait -family будут сообщать вам, какой из них вышел).

Конечно, если вся ваша модель должна использовать отдельный процесс для каждого подключения, я не уверен, почему вам нужно идентифицировать соединения вообще в родительском процессе. Если каждое соединение не является полностью независимым процессом, вы можете сделать намного лучше, используя streamи вместо процессов.