/* Server de stocuri. Este un server cu un singur proces, deci * un server concurent. El foloseste transport TCP si apelul * sistem select */ #include #include #include #include #include #include #include #include extern int errno; /* Indicator de erori apelurilor sistem */ #define ERR(S,N) {fprintf(stderr,"\n%d\n",N);\ perror(S);exit(N);} #define PORT_STOC 7777 /* Numarul de port */ /* Structura unei pozitii din stoc */ struct element_stoc { char produs[32]; /* Numele produsului */ long cantitate; /* Nivelul stocului */ }; /* Baza de date cu stocurile */ #define MAX_POZITII 1000 /* Numarul maxim de pozitii in stoc */ struct element_stoc lista_stocuri[MAX_POZITII]; main () { int sock, fd, addrlen; struct sockaddr_in server, client; int max_fd; FILE **stream; struct rlimit limit_info; /* Acestea sunt multimile de descriptori folosite de select() */ fd_set test_set, ready_set; /* Este necesar un tablou de descriptori de stream (de tip * FILE*). Deoarece nu se stie apriori cat de multi descriptori * pot fi deschisi (asta depinde de implementarea concreta a SO), * se va determina dinamic aceasta valoare, folosind getlimit(), * si se va aloca dinamic tabloul de dimensiunea ceruta */ if (getrlimit (RLIMIT_NOFILE, &limit_info) < 0) ERR ("getrlimit", 1); if ((stream = (FILE **) malloc (limit_info.rlim_cur * sizeof (FILE *))) < 0) ERR ("malloc", 2); if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) ERR ("socket", 3); server.sin_family = AF_INET; server.sin_addr.s_addr = htonl (INADDR_ANY); server.sin_port = htons (PORT_STOC); if (bind (sock, (struct sockaddr *) &server, sizeof (server)) < 0) ERR ("bind", 4); listen (sock, 5); max_fd = sock; /* Initial, multimea test_set are numai descriptorul de * intalnire */ FD_ZERO (&test_set); FD_SET (sock, &test_set); /* Sfarsitul listei este marcat printr-o intrare negativa la * nivelul stocului. Marcam initial aceasta lista ca fiind vida */ lista_stocuri[0].cantitate = -1; /* Bucla principala (de asteptare) a serverului */ for (;;) { /* Deoarece select suprascrie multimea de descriptori, trebuie * sa folosim aici o copie a acesteia */ memcpy (&ready_set, &test_set, sizeof (test_set)); select (max_fd + 1, &ready_set, NULL, NULL, NULL); /* A aparut o noua cerere? Ea este acceptata si se adauga noul * descriptor la setul de read */ if (FD_ISSET (sock, &ready_set)) { addrlen = sizeof (client); fd = accept (sock, (struct sockaddr *) &client, &addrlen); FD_SET (fd, &test_set); if (fd > max_fd) max_fd = fd; stream[fd] = fdopen (fd, "r+"); } /* Acum se verifica fiecare descriptor din setul de read. Daca * este ready, se prelucreaza cererea clientului. De remarcat ca * NU se controleaza descriptorul de intalnire */ for (fd = 0; fd <= max_fd; fd++) { if ((fd != sock) && FD_ISSET (fd, &ready_set)) { if (prelucrare_stoc (stream[fd], fd) >= 0) { fflush (stream[fd]); } else { /* Daca clientul si-a inchis conexiunea, atunci se sterge din * multime descriptorul corespunzator */ close (fd); FD_CLR (fd, &test_set); } } } } } #include "prelucrare_stoc.c" /* Programul 3.16 Sursa serverului stocuri.c */