programowanie_uslug_sieciowych:tcp_client_server_application

Pytanie: “Przedstaw i omów algorytm budowy podstawowej aplikacji klient-serwer dla połączeń TCP/IP.”

:wersja pdf

# Protokół TCP

Protokół TCP (ang. Transmission Control Protocol) to połączeniowy i niezawodny protokół 4. warstwy modelu OSI (czyli warstwy transportowej). Jest to protokół połączniowy, gdyż przed wymianą danych należy stworzyć połączenie za pomocą mechanizmu three-way handshake. Jest to również protokół niezawodny, gdyż każde wysłane dane muszą być potwierdzone. W przypadku braku potwierdzenia dane są wysyłanie ponownie. Jeśli dostarczenie danych jest niemożliwe, to protokół informuje o tym. Protokół TCP oferuje również kontrolę przypływu danych (ang. flow control). Każdy uczestnik połączenia informuję drugą stronę o tym ile danych może w danej chwili odebrać. No i ostatnia cecha protokołu TCP to pełna dwukierunkowość przesyłu danych (ang. full-duplex).

## Serwer

Algorytm serwera TCP przedstawia się następująco:

- Stwórz gniazdo połączeniowe (`SOCK_STREAM`)
- Przypisz gniazdo do portu
- Zacznij nasłuchiwać
- Rozpocznij pętlę:
  - Akceptuj połączenie
  - Stwórz nowy proces do obsługi klienta, który:
    - Zamknie gniazdo nasłuchujące (nie jest potrzebne do obsługi klienta)
    - Rozpocznie pętlę:
      - Odbierze przychodzące dane
      - Przetwórz dane
      - Odeślij odpowiedź
  - Zamknij gniazdo połączone (nie jest potrzebne serwerowi)

## Klient

Algorytm klienta TCP przedstawia się następująco:

- Stwórz gniazdo połączeniowe (`SOCK_STREAM`)
- Połącz się z serwerem
- Rozpocznij pętlę:
  - Wyślij zapytanie
  - Odbierz odpowiedź
  - Przetwórz odpowiedź

## Funkcje

Drugi parametr funkcji `socket()` określa typ tworzonego gniazda. Do utworzenia gniazda połączeniowego wykorzystuje się następujące wywołanie:

        int sockfd = socket(PF_INET, SOCK_STREAM, 0);

Aby przypisać gniazdo do portu, należy przygotować strukturę `struct sockaddr` i wywołać funkcję `bind()`:

        bind(sockfd, (struct sockaddr *) &my_addr, sizeof(my_addr));

Aby socket stał się socketem nasłuchującym należy wywołać funkcję `listen()`. Jej argumenty to: socket który ma stać się socketem nasłuchującym, wartość określająca maksymalną dozwoloną ilość połączeń oczekujących na zaakceptowanie:

        listen(sockfd, 10);

Klient rozpoczyna połączenie wywołując funkcję `connect()`. Funkcja ta zapoczątkuje mechanizm three-way handshake z serwerem. Wynikiem jej wywołania będzie wysłanie do serwera segmentu TCP z ustawioną flagą `SYN`. Parametry tej funkcji to: socket który ma być uczestnikiem połączenia, wskaźnik do struktury `sockaddr` (i jej rozmiar) w której znajdują się informacje o serwerze:

        connect(sockfd, (struct sockaddr *) &server_addr,
                sizeof(server_addr));

Serwer odpowiada na rozpoczęcie mechanizmu three-way handshake funkcją `accept()`. Wynikiem jej wywołania będzie wysłanie do klienta segmentu TCP z ustawionymi flagami `SYN` i `ACK`. Po otrzymaniu tego segmentu klient zakończy mechanizm three-way handshake odsyłając segment TCP z ustawioną flagą `ACK`. Argumenty funkcji `accept()` to: socket nasłuchujący, wskaźnik do struktury `sockaddr` (i jej rozmiar) do której zostaną zapisane informacje o kliencie. Funkcja zwraca socket połączony, który będzie służył do komunikacji z klientem:

        new_fd = accept(sockfd, (struct sockaddr *) &client_addr,
                        &client_addr_len);

Dane wysyła się za pomocą funkcji `send()`. Jej argumenty to: socket połączony przez który będą wysyłane dane, wskaźnik do bufora (i jego długość) z którego będą pobrane dane do wysłania, flagi (zwykle 0):

        send(new_fd, buf, strlen(buf), 0);

Dane odbiera się za pomocą funkcji `recv()`. Jej argumenty to: socket połączony z którego dane będą czytane, wskaźnik do bufora (i jego długość) do którego trafią dane, flagi (zwykle 0):

        recv(sockfd, buf, MAXBUFLEN-1, 0)

Powyższe funkcje w przypadku wystąpienia błędu zwracają -1 i ustawiają zmienną `errno`.

## Dodatkowe informacje

- http://beej.us/guide/bgnet/output/htmlsingle/bgnet.html – programowanie sieciowe
- http://en.wikipedia.org/wiki/Berkeley_sockets – programowanie sieciowe