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


{{:programowanie_uslug_sieciowych:14.7.pdf|: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//).

{{ :programowanie_uslug_sieciowych:tcpapp.png|:programowanie_uslug_sieciowych:tcpapp.png}}

===== 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:
<code c>
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
</code>

Aby przypisać gniazdo do portu, należy przygotować strukturę ''struct sockaddr'' i wywołać funkcję ''bind()'':
<code c>
    bind(sockfd, (struct sockaddr *) &my_addr, sizeof(my_addr));
</code>

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:
<code c>
    listen(sockfd, 10);
</code>

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:
<code c>
    connect(sockfd, (struct sockaddr *) &server_addr,
            sizeof(server_addr));
</code>

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:
<code c>
    new_fd = accept(sockfd, (struct sockaddr *) &client_addr,
                    &client_addr_len);
</code>

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):
<code c>
    send(new_fd, buf, strlen(buf), 0);
</code>

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):
<code c>
    recv(sockfd, buf, MAXBUFLEN-1, 0)
</code>

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