Gniazda sieciowe w BASH -------------------------------------- Gniazda sieciowe ******************** 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: * typ gniazda, związany z protokołem wymiany danych (np. Stream socket wykorzystujący TCP lub Datagram socket wykorzystujący UDP) * adres (np. adres IP) * opcjonalny numer portu 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. Narzędzie ``telnet`` (klient) ******************** 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``. Narzędzie ``ncat`` (serwer) *************** 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. Zadanie 1 *************** 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``. Dodatkowe *************** 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`` .. code-block:: bash #!/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`` .. code-block:: bash #!/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 BASH --- klient *************** 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. .. code-block:: bash # 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. BASH --- zdanie *************** Proszę postarać się do końca zajęć napisać dwa programy: * ``simple-list.sh``, który łączy się z serwerem i pobiera listę wiadomości. * ``simple-post.sh "moja wiadomość"``, który łączy się z serwerem i ustawia wiadomość.