Chciałem prosić o pomoc przy pisaniu programu klient-serwer. Sprawa wygląda następująco:
- tworzę dwa programy: serwer współbieżny i klient
- ich działanie ma polegać na tym, że uruchamiam serwer a następnie uruchamiam program klienta z parametrem, którym jest ciąg znaków (do 255), klient przesyla następnie zapytanie do serwera (składające się ze wspomnianego ciągu znaków i PID klienta), który odsyła klientowi jako odpowiedź ilość małych znaków w tym ciągu znaków
- serwer po uruchomieniu tworzy FIFO prywatne do którego klienci mogą zapisywać swoje zapytania, a serwer je stamtąd odczytuje
- każdy klient tworzy własne FIFO prywatne (postaci /tmp/FIFO_[nr_PID_klienta]) do którego przesyła odpowiedź serwer (czyli liczbę oznaczającą ilość małych znaków w przesłanym mu tekście) i z którego odczytuje ją każdy z klientów
- serwer w założeniu ma być serwerem współbieżnym czyli powinien być w stanie obsługiwać kilku klientów na raz
Mój problem polega na tym, że nie jestem w stanie sprawić by ten serwer był serwerem współbieżnym (wersję iteracyjną udało mi się zrobić). Zamieszczam tu kod programu klienta i serwera, ale serwer po przyjęciu pierwszego zgłoszenia od klienta zaczyna tworzyć ogromną ilość procesów potomnych i trzeba szybko przerywać jego pracę. Próbowałem już różnych rzeczy, szukałem informacji w internecie i książkach ale cały czas nie wiem w jaki sposób sprawić by to działało.
/*SERWER*/
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<unistd.h>
#include<ctype.h>
#include<string.h>
#include<errno.h>
#define FIFO_PUBLICZNE "/tmp/FIFO_30438"
#define MAX 256
#define TRUE 1
int do_odczytu, do_zapisu, deskr_fpryw, ile_przeczytano, ile_zapisano, wynik, pid, jaki_wynik,
nr_proc, liczba_potomkow = 0;
char fifo_prywatne[15];
struct wiadomosc {
pid_t pid_proc;
char znaki[MAX];
};
struct wiadomosc msg;
void obsluga_bledu_mkfifo(int jaki_wynik);
int ile_malych(char ciag[], int length);
void proces_potomny();
int main(int argc, char *argv[]) {
/*
tworzy FIFO publiczne do ktorego swoje zapytania beda zapisywali
klienci a serwer bedzie je odczytywal
*/
printf("## Tworze FIFO publiczne\n");
obsluga_bledu_mkfifo(mkfifo(FIFO_PUBLICZNE, 0666));
/*otwiera FIFO publiczne do odczytu*/
do_odczytu = open(FIFO_PUBLICZNE, O_RDONLY);
printf("Deskryptor do_odczytu: %d\n", do_odczytu);
/*otwiera FIFO publiczne do zapisu, co nie bedzie wykorzystywane*/
do_zapisu = open(FIFO_PUBLICZNE, O_WRONLY);
printf("Deskryptor do_zapisu: %d\n", do_zapisu);
while(TRUE) {
pid = fork();
if(pid == 0) {
proces_potomny();
}
else if(pid == -1) {
printf("Blad\n");
exit(1);
}
liczba_potomkow++;
while(liczba_potomkow) {
nr_proc = waitpid(-1, NULL, WNOHANG);
if(nr_proc == -1) {
printf("Blad waitpid()!\n");
}
else if(nr_proc == 0) {
break;
}
else {
liczba_potomkow--;
}
}
}
}
void proces_potomny() {
/*serwer czyta z FIFO publicznego zapytanie wyslane przez klienta*/
ile_przeczytano = read(do_odczytu, &msg, (MAX+4));
printf("Przeczytane znaki: %s\n", msg.znaki);
/*
serwer oblicza ilosc malych znakow w przeslanym przez
klienta ciagu znakow
*/
printf("## Obliczam ilosc malych znakow w tekscie otrzymanym od klienta... ");
wynik = ile_malych(msg.znaki, ile_przeczytano);
printf("Zakonczylem obliczanie.\n");
sprintf(fifo_prywatne, "/tmp/FIFO_%d", msg.pid_proc);
/*usypiam serwer na 1sek, by klient zdazyl utworzyc FIFO prywatne*/
sleep(1);
/*
otworzenie FIFO prywatnego, do ktorego zostanie
zapisana odpowiedz dla klienta
*/
printf("## Otwieram FIFO prywatne do zapisu... ");
deskr_fpryw = open(fifo_prywatne, O_WRONLY);
printf("Otworzylem.\n");
printf("Deskryptor: %d\n", deskr_fpryw);
/*
zapisanie odpowiedzi do FIFO prywatnego,
kazdy serwer ma swoje wlasne FIFO prywatne
*/
printf("## Zapisuje wynik do FIFO prywatnego... ");
ile_zapisano = write(deskr_fpryw, &wynik, MAX);
printf("Zapisalem.\n");
close(do_odczytu);
close(deskr_fpryw);
_exit(0);
}
void obsluga_bledu_mkfifo(int jaki_wynik) {
if(jaki_wynik == 0) {
printf("## Utworzono FIFO publiczne: %s\n", FIFO_PUBLICZNE);
}
else if(jaki_wynik < 0) {
switch(errno) {
case EROFS:
printf("## System plikow jedynie do odczytu.",
"Nie mozna utworzyc FIFO.\n");
case ENOSPC:
printf("## Brak miejsca na dysku.",
"Nie mozna utworzyc FIFO.\n");
case EACCES:
printf("## Jeden z katalogow podanych w sciezce",
"nie ma ustawionych uprawnien do przeszukiwania\n");
case EEXIST:
printf("## FIFO publiczne juz istnieje.\n");
}
}
}
int ile_malych(char ciag[], int length) {
int i, ile_mal=0;
for(i=0; i<length; i++) {
if(islower(ciag[i])) {
ile_mal++;
}
}
return ile_mal;
}
/*KLIENT*/
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<ctype.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#define FIFO_PUBLICZNE "/tmp/FIFO_30438"
#define MAX 256
void obsluga_bledu_mkfifo(int jaki_wynik, char nazwa_fifo_pryw[]);
int ile_zapisano, ile_odczytano, deskr_fpubl, deskr_fpryw, wynik;
char fifo_prywatne[15];
struct wiadomosc {
pid_t pid_proc;
char znaki[MAX];
};
struct wiadomosc msg;
int main(int argc, char *argv[]) {
if(argc == 1) {
printf("Blad! Musisz podac parametr.\n");
}
else if(argc > 2) {
printf("Blad! Musisz podac tylko jeden parametr.\n");
}
else if(argc==2) {
/*zapisuje w strukturze msg pid klienta*/
msg.pid_proc = getpid();
/*
zapisuje w strukturze msg ciag znakow podanych jako parametr
podczas uruchomienia klienta
*/
strcpy(msg.znaki, argv[1]);
/*otwiera FIFO publiczne do zapisu*/
printf("## Otwieram FIFO publiczne do zapisu... ");
deskr_fpubl = open(FIFO_PUBLICZNE, O_WRONLY);
printf("Otworzylem.\n");
printf("Deskryptor: %d.\n", deskr_fpubl);
/*zapisuje do FIFO publicznego strukture msg*/
printf("## Zapisuje do FIFO publicznego... ");
ile_zapisano = write(deskr_fpubl, &msg, (MAX+4));
printf("Zakonczylem zapisywanie.\n");
sprintf(fifo_prywatne, "/tmp/FIFO_%d", msg.pid_proc);
/*
tworzy FIFO prywatne, do ktorego serwer zapisze
odpowiedz i z ktorego nastepnie klient ja odczyta
*/
printf("## Tworze FIFO prywatne.\n");
obsluga_bledu_mkfifo(mkfifo(fifo_prywatne, 0666), fifo_prywatne);
/*klient otwiera do odczytu FIFO prywatne*/
printf("## Otwieram FIFO prywatne do odczytu... \n");
deskr_fpryw = open(fifo_prywatne, O_RDONLY);
printf("Deskryptor: %d\n", deskr_fpryw);
printf("Otworzylem.\n");
/*
klient odczytuje z FIFO prywatnego
przeslana przez serwer odpowiedz
*/
printf("## Odczytuje z FIFO prywatnego wynik... ");
ile_odczytano = read(deskr_fpryw, &wynik, MAX);
printf("Odczytalem.\n");
printf("Liczba malych liter we wprowadzonym tekscie: %d\n", wynik);
close(deskr_fpubl);
close(deskr_fpryw);
exit(0);
}
}
void obsluga_bledu_mkfifo(int jaki_wynik, char nazwa_fifo_pryw[]) {
if(jaki_wynik == 0) {
printf("## Utworzono FIFO prywatne: %s\n", nazwa_fifo_pryw);
}
else if(jaki_wynik < 0) {
switch(errno) {
case EROFS:
printf("## System plikow jedynie do odczytu.",
"Nie mozna utworzyc FIFO.\n");
case ENOSPC:
printf("## Brak miejsca na dysku.",
"Nie mozna utworzyc FIFO.\n");
case EACCES:
printf("## Jeden z katalogow podanych w sciezce",
"nie ma ustawionych uprawnien do przeszukiwania\n");
case EEXIST:
printf("## FIFO prywatne juz istnieje\n");
}
}
}