# Lista 9 ###### tags: `SO` ## Zadanie 1 Warstwy: - łącza przekierowuje przez serię routerów między źródłem a celem - sieciowa - transportowa Transportuje wiadomości z warstwy aplikacji pomiędzy końcami aplikacji. Protokoły warstwy łącza zajmują się komunikacją między urządzeniami w sieci lokalnej. Służą one do tworzenia połączenia między komputerami, urządzeniami sieciowymi i innymi urządzeniami podłączonymi do tej samej sieci. Protokoły te działają na fizycznym poziomie sieci i zapewniają wymianę danych między poszczególnymi urządzeniami. Protokoły warstwy sieciowej zajmują się przesyłaniem danych pomiędzy różnymi sieciami. Służą one do tworzenia połączenia między różnymi sieciami, takimi jak sieć lokalna i internet, i zapewniają możliwość przesyłania danych między nimi. Protokoły warstwy sieciowej działają na poziomie sieci i zapewniają wymianę danych pomiędzy różnymi sieciami. Protokoły warstwy transportowej zapewniają sprawną komunikację między aplikacjami i poszczególnymi hostami w sieci. Służą one do tworzenia połączenia między aplikacjami i zapewniają możliwość przesyłania danych pomiędzy nimi. Protokoły warstwy transportowej działają na poziomie transportu i zapewniają wymianę danych pomiędzy aplikacjami. Protokoły warstwy łącza i sieciowej nie są używane do komunikacji między procesami użytkownika, ponieważ te protokoły działają na niższych poziomach modelu OSI i zajmują się przesyłaniem danych między urządzeniami w sieci. Komunikacja między procesami użytkownika jest zazwyczaj realizowana przez protokoły warstwy aplikacji, które działają na wyższym poziomie modelu OSI i umożliwiają bezpośrednią komunikację między aplikacjami. ## Zadanie 2 1. udp - brak gwarancji dotarcia, kolejności i pojedynczego dotarcia - brak automatycznej retransmisji - każdy datagram ma długość, przekazywaną wraz z danymi - strumień bajtów 2. tcp - stałe połączenie między klientem a serwerem - oczekuje potwierdzenia odbioru, retransmituje kilka razy przed poddaniem się - sekwencjonuje dane Półdupleks - dane mogą być przesyłane w obie strony, ale tylko w jednym kierunku jednocześnie. Dupleks - dane mogą być przesyłane w obie strony jednocześnie flow control - TCP mówi, ile bajtów może przyjąć na raz ## Zadanie 3 ![](https://i.imgur.com/MuDgAkO.png) **W którym momencie następuje związanie gniazda z adresem lokalnym i zdalnym?** Przy wywołaniu bind. **Która ze stron komunikacji używa portów ulotnych (ang. ephemeral)?** Obie. **Co specyfikuje drugi argument wywołania systemowego listen(2)?** Maksymalną długość kolejki oczekujących połączeń. **Z jakim numerem portu jest związane gniazdo przekazywane do i zwracane z accept(2)?** Z różnym. **Skąd serwer wie, że klient zakończył połączenie?** Klient wysyła mu tą informację jako EOF. ## Zadanie 4 ![](https://i.imgur.com/5Gtb7FL.png) **Czemu, w przeciwieństwie do TCP, serwer może rozpocząć pracę zaraz po wykonaniu funkcji bind(2)?** Ten protokół jest znacznie prostszy i nie potrzebuje stabilnego połączenia między klientem a serwerem, opiera się na pojedynczych wysyłanych danych. **Z jakiej przyczyny interfejs read(2) i write(2) po stronie serwera może być niewystarczający?** Potrafimy obsługiwać tylko jednego klienta na raz. **Przedstaw semantykę operacji recvfrom(2) i sendto(2).** Pierwsze odbiera wiadomość, drugie wysyła wiadomość. **Kiedy po stronie klienta następuje związanie gniazda UDP z adresem lokalnym?** W momencie wysłania danych. **Na podstawie [7, 8.11] zreferuj efekt jaki przynosi wykonanie connect(2) na gnieździe klienta.** Zapisanie adresu IP i numeru portu. Nie możemy już używać `sendto` (ponieważ adres jest znany i ustalony) Nie musimy używać `recvfrom`. **Jakie ograniczenia poprzednio wymienionych funkcji zostały poprawione przez wywołania recvmsg(2) i sendmsg(2)?** Dane mają teraz konkretniejszą strukturę. ## Zadanie 5 ## Zadanie 6 ## Zadanie 7 ## Zadanie 8 ```c= #include "csapp.h" #include "rio.h" #define LISTENQ 10 #define MAXCLIENTS (PAGE_SIZE / sizeof(client_t)) typedef struct client { pid_t pid; /* Client process id */ size_t nread; /* Numer of bytes received so far */ } client_t; /* TODO: Need to define context to be used with sigsetjmp & siglongjmp. */ static client_t *client = NULL; static sig_atomic_t nclients = 0; static size_t nread = 0; /* number of bytest received on all connections */ static jmp_buf env; static client_t *findclient(pid_t pid) { for (int i = 0; i < MAXCLIENTS; i++) if (client[i].pid == pid) return &client[i]; return NULL; } static client_t *addclient(void) { client_t *c = findclient(0); if (c) { c->pid = -1; /* XXX: must be filled in after fork */ c->nread = 0; nclients++; } return c; } static void delclient(pid_t pid) { client_t *c = findclient(pid); assert(c != NULL); nread += c->nread; c->pid = 0; nclients--; } static void sigchld_handler(int sig) { pid_t pid; /* TODO: Delete clients as they die. */ pid = Wait(NULL); safe_printf("[%d] Disconnected!\n", pid); delclient(pid); return; } static void sigint_handler(int sig) { safe_printf("Server received quit request!\n"); /* TODO: Change control flow so that it does not return to main loop. */ siglongjmp(env, 0); } static void echo(client_t *c, int connfd) { size_t n; char buf[MAXLINE]; rio_t rio; rio_readinitb(&rio, connfd); while ((n = Rio_readlineb(&rio, buf, MAXLINE))) { Rio_writen(connfd, buf, n); c->nread += n; /* XXX: Uncomment line below and watch client behaviour. */ /* exit(0); */ } } int main(int argc, char **argv) { if (argc != 2) app_error("usage: %s <port>\n", argv[0]); sigset_t sig_mask; sigemptyset(&sig_mask); sigaddset(&sig_mask, SIGCHLD); Signal(SIGCHLD, sigchld_handler); Signal(SIGINT, sigint_handler); client = Mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); int listenfd = Open_listenfd(argv[1], LISTENQ); /* TODO: Wait for all clients to quit and print a message with nread. */ if (sigsetjmp(env, 1)) { while (nclients > 0) { } safe_printf("Server received %d bytes\n", nread); exit(EXIT_SUCCESS); } while (1) { socklen_t clientlen = sizeof(struct sockaddr_storage); struct sockaddr_storage clientaddr; /* Enough space for any address */ int connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); static char client_hostname[MAXLINE], client_port[MAXLINE]; Getnameinfo((SA *)&clientaddr, clientlen, client_hostname, MAXLINE, client_port, MAXLINE, 0); sigset_t mask; Sigprocmask(SIG_BLOCK, &sig_mask, &mask); /* TODO: Start client in subprocess, close unused file descriptors. */ client_t *c = addclient(); pid_t pid = Fork(); if(pid) { // Parent Close(connfd); } else { // Child Close(listenfd); Signal(SIGINT, NULL); c->pid = getpid(); echo(c, connfd); exit(EXIT_SUCCESS); } printf("[%d] Connected to %s:%s\n", pid, client_hostname, client_port); Sigprocmask(SIG_SETMASK, &mask, NULL); } } ```