# 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

**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

**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);
}
}
```