Gniazdo (ang. socket) jest to abstrakcyjne pojęcie reprezentujące dwukierunkowy punkt końcowy sieciowego połączenia pomiędzy odległymi procesami. Dwukierunkowe, gdyż umożliwia zarówno (1) wysyłanie i (2) odbieranie danych.
Podstawowe właściwości każdego gniazda:
Procesy które zapewniają różne usługi przy użyciu gniazd nazywamy serwerami. W przypadku takich procesów stosowane są gniazda w trybie nasłuchiwania: czekają i nasłuchują, kiedy podłączy się do nich proces klienta.
Telnet jest narzędziem pozwalającym wykonywać połączenia TCP z serwerem. Jest więc programem typu “klient”.
Składnia najprostrzego połączenia:
telnet ADRES_IP PORT
Czyli by połączyć się do serwera google.pl serwującego strony internetowe (standardowym portem HTTP jest port 80), możemy napisać w terminalu:
telnet google.pl 80
Przykład: by uzyskać stronę internetową serwowaną przez serwer musimy wysłać zapytanie HTTP:
GET / HTTP/1.0
(oraz nacisnąć ENTER 2 razy!)
Alternatywnie, by połączyć się z gniazdem na własnym komputerze zamiast adresu IP można użyć słowa localhost.
By tworzyć serwer (gniazdo nasłuchujące) na własnym komputerze można użyć programu ncat.
Przykładowo:
ncat -l 8000 -k -e skrypt.sh
tworzy serwer na porcie 8000, serwer ten dla każdego przychodzącego połączenia wykonuje skrypt skrypt.sh.
Możemy sprawdzić ich działanie za pomocą połączenia telnet.
Stworzyć serwer działający na porcie 8000, który wyśle słowo HELLO! do każdego procesu, który się do niego podłączy (należy napisać skrypt hello.sh oraz użyć polecenia ncat). Należy przetestować jego działanie przy użyciu programu telnet.
Programy te sprawiają, że w bashu można dość łatwo tworzyć rozwiązania sieciowe. Rozważmy takie dwa programy:
Pierwszy nazywa się server-simple.sh
#!/bin/bash
FILE="/tmp/chatroom-simple"
function read_message {
__IFS=$IFS
IFS=
read message
IFS=${__IFS}
echo ${message}
}
echo "submit your message"
message=$(read_message)
echo "${message}" >> ${FILE}
Note
polecenie read odczytuje wartość jednej zmiennej z standardowego wejścia, domyślnie zmienne separowane są spacjami, zmienna IFS pozwala kontrolować jak bash tokenizuje ciągi znaków.
Ustawienie IFS= powoduje że polecenie read odczyta całe standardowe wejście.
Program ten odczytuje linijkę tekstu i zapisuje ją do pliku.
Drugi nazywa się server-read-simple.sh
#!/bin/bash
FILE="/tmp/chatroom-simple"
cat $FILE
Skrypt ten odczytuje plik z dysku i go wyświetla.
Proszę zauważyć że dwóch użytkowników, może za pomocą tych dwóch programów chatować (o ile obaj użytkownicy działają na jednym komputerze).
Teraz chcielibyśmy udostępnić te dwa programy jako usługi sieciowe za pomocą TCP:
ncat -l 8000 -k -e server-simple.sh
ncat -l 8001 -k -e server-read-simple.sh
Teraz chcielibyśmy opracować klienta, tak bym mógł napisać ./list-messages.sh i otrzymać listę wiadomości.
W linuksach istnieje magiczna struktura /dev/tcp/host/port, zawierająca pliki pozwalające na wykonywanie połączeń TCP.
Note
Do tej pory mówiliśmy że program ma trzy przypisane do niego strumienie (standardowe wejście, standardowe wyjście oraz standardowe wyjście błędu).
Takich strumieni może być dowolnie wiele. Możemy sami je definiować.
Polecenie exec 5<> NAZWA_PLIKU spowoduje że do wejścia numer 5 zostanie podłączony plik NAZWA_PLIKU (zawartość pliku zostanie tam przesłana) a dane wysłane na wyjścia numer 5 trafią do tego pliku.
# Ustawiamy że para wejście i wyjście numer 5 będzie przypięte do
# połączenia TCP z hostem google.pl na porcie 80
exec 5<>/dev/tcp/google.pl/80
# Wysyłamy zapytanie HTTP
echo -e "GET / HTTP/1.0\n" >&5
# Wyświetlamy to co serwer nam odpowiedział.
cat <&5
W taki sam sposób mogę oprogramować klienta naszego chatu.
Proszę postarać się do końca zajęć napisać dwa programy: