Ha a képzési hálóban a tárgyak kovalens kötéssel kapcsolódnának, akkor a ráépülő Hálózatok tárgy felé az alábbi példa feldolgozásával kötünk majd. Ez egy egyszerű hálózati TCP/IP szerverprogi, amit próbáltunk állatorvosi módon elkészíteni, mert lesz benne:
- fork
- socket programozás (UNIX-ban minden fájl)
- multiplexelés (a select rendszerhívás)
- jelkezelés
- szemaforok
- osztott memória használata
A program első iniciális változatának összedobása után lássuk a tesztelést:
Eddig ez kíméletes volt, de laborkísérletezzünk vele: a kliens nyomja párhuzamosabban, vegyük ki/be a szemaforos védelmet a szerveren és tegyünk be egy kis alvós késleltetést a kiszolgálásba! Miket tapasztalunk? Egy trófea annak, aki demonstrálja, hogy elromlik az örök válasz: a 42.
Lapozz tovább a forrásokért:
szerver.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <time.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <sys/select.h> #include <sys/time.h> #include <signal.h> #include <errno.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/stat.h> #include <sys/shm.h> #include <sys/wait.h> #define SZERVER_PORT 2006 #define SZERVER_SOR_MERET 10 #define CTIME_BUFFER_MERET 128 int kiszolgal (int kliens, int szemafor, int *osztott_memoria_terulet) { char buffer[CTIME_BUFFER_MERET] = ""; time_t t = time (NULL); char *ts = ctime_r (&t, buffer); char buffer2[256] = ""; struct sembuf zar, nyit; zar.sem_num = 0; zar.sem_op = -1; nyit.sem_num = 0; nyit.sem_op = 1; int olvasott = read (kliens, buffer2, 10); write (kliens, buffer2, olvasott); if (semop (szemafor, &zar, 1) == -1) { perror ("semop"); exit (EXIT_FAILURE); } ++*(osztott_memoria_terulet+1); if (buffer2[0] == '+') ++*osztott_memoria_terulet; else --*osztott_memoria_terulet; olvasott = snprintf(buffer2, 50, "Ertek=%d Kliensek=%d\n", *osztott_memoria_terulet, *(osztott_memoria_terulet+1)); // debug // printf ("%d\n", *osztott_memoria_terulet); // fflush (stdout); if (semop (szemafor, &nyit, 1) == -1) { perror ("semop"); exit (EXIT_FAILURE); } write (kliens, buffer2, olvasott); return write (kliens, ts, strlen (ts)); } void zombi_elharito (int sig) { while (wait (NULL) > 0) ; } int main (void) { int kapu_figyelo, kapcsolat, kliensm, sockoptval = 1, s, gyermekem_pid, szemafor; fd_set kapu_figyelok; int osztott_memoria; int *osztott_memoria_terulet; struct timeval timeout; struct sockaddr_in szerver, kliens; struct sigaction sa; sa.sa_handler = zombi_elharito; sigemptyset (&sa.sa_mask); sa.sa_flags = SA_RESTART; memset ((void *) &szerver, 0, sizeof (szerver)); szerver.sin_family = AF_INET; inet_aton ("127.0.0.1", &(szerver.sin_addr)); szerver.sin_port = htons (SZERVER_PORT); if ((kapu_figyelo = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { perror ("socket"); exit (EXIT_FAILURE); } setsockopt (kapu_figyelo, SOL_SOCKET, SO_REUSEADDR, (void *) &sockoptval, sizeof (sockoptval)); fcntl (kapu_figyelo, F_SETFL, fcntl (kapu_figyelo, F_GETFL) | O_NONBLOCK); if (bind (kapu_figyelo, (struct sockaddr *) &szerver, sizeof (szerver)) == -1) { perror ("bind"); exit (EXIT_FAILURE); } if (listen (kapu_figyelo, SZERVER_SOR_MERET) == -1) { perror ("listen"); exit (EXIT_FAILURE); } printf ("%s:%d\n", inet_ntoa (szerver.sin_addr), ntohs (szerver.sin_port)); if ((szemafor = semget (ftok (".", 42), 1, IPC_CREAT | S_IRUSR | S_IWUSR)) == -1) { perror ("semget"); exit (EXIT_FAILURE); } printf ("szemafor: %d\n", szemafor); fflush (stdout); if (semctl (szemafor, 0, SETVAL, 1)) { perror ("semctl"); exit (EXIT_FAILURE); } if ((osztott_memoria = shmget (ftok (".", 44), 2*sizeof(int), IPC_CREAT | S_IRUSR | S_IWUSR)) == -1) { perror ("shmget"); exit (EXIT_FAILURE); } if ((osztott_memoria_terulet = (int *)shmat (osztott_memoria, NULL, 0)) < 0) { perror ("shmat"); exit (EXIT_FAILURE); } *osztott_memoria_terulet = 42; *(osztott_memoria_terulet+1) = 0; sigaction (SIGCHLD, &sa, NULL); FD_ZERO (&kapu_figyelok); for (;;) { FD_SET (kapu_figyelo, &kapu_figyelok); timeout.tv_sec = 3; timeout.tv_usec = 0; if ((s = select (kapu_figyelo + 1, &kapu_figyelok, NULL, NULL, &timeout)) == -1) { switch (errno) { case EBADF: printf ("EBADF\n"); break; case EINTR: printf ("EINTR\n"); break; case EINVAL: printf ("EINVAL\n"); break; case ENOMEM: printf ("ENOMEM\n"); break; } fflush (stdout); //exit (EXIT_FAILURE); } else if (!s) { printf ("vartam...\n"); fflush (stdout); } else { if (FD_ISSET (kapu_figyelo, &kapu_figyelok)) { memset ((void *) &kliens, 0, (kliensm = sizeof (kliens))); if ((kapcsolat = accept (kapu_figyelo, (struct sockaddr *) &kliens, (socklen_t *) & kliensm)) == -1) { perror ("accept"); exit (EXIT_FAILURE); } printf (" <-> %s:%d\n", inet_ntoa (kliens.sin_addr), ntohs (kliens.sin_port)); if ((gyermekem_pid = fork ()) == 0) { close (kapu_figyelo); if (kiszolgal (kapcsolat, szemafor, osztott_memoria_terulet) == -1) { perror ("kiszolgal"); } close (kapcsolat); exit (EXIT_SUCCESS); } else if (gyermekem_pid > 0) { // wait(&statusz); e miatt kezeljuk a SIGCHLD jelet, // l. a Zombik fejezetet! close (kapcsolat); } else { close (kapcsolat); perror ("fork"); exit (EXIT_FAILURE); } } } } }
kliens.c
#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define SZERVER_PORT 2006 #define BUFFER_MERET 256 int kliens (char b) { int kapu, olvasva; struct sockaddr_in szerver; char buffer[BUFFER_MERET]; memset ((void *) &szerver, 0, sizeof (szerver)); szerver.sin_family = AF_INET; inet_aton ("127.0.0.1", &(szerver.sin_addr)); szerver.sin_port = htons (SZERVER_PORT); if ((kapu = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { perror ("socket"); return -1; } if (connect (kapu, (struct sockaddr *) &szerver, sizeof (szerver)) == -1) { perror ("connect"); return -1; } write(kapu, &b, 1); write(kapu, &b, 1); while ((olvasva = read (kapu, buffer, BUFFER_MERET)) > 0) write (1, buffer, olvasva); return 0; } int main (int argc, char *argv[]) { for (int i=0; i<1000; ++i) kliens(argv[1][0]); exit (EXIT_SUCCESS); }
(Ha valami nem világos, még nem probléma, az érintett témákat az 5. előadáson tárgyaljuk.)