SK Zadanie 3 remoteFrom Łukasz Graczykowski(Difference between revisions)
Revision as of 14:16, 5 November 2020
ZadaniaZadanie 1Stworzyć 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. Zadanie 2Uruchomić program w środowisku eclipse. Następnie, należy polączyć się z serwerem www.pw.edu.pl na porcie 80. Na ekran należy wypisać tylko te linijki które zawierają słowo body. Zadanie 3Uruchomić program w środowisku eclipse. Przerobić program w taki sposób, by do tekstu wysyłanego przez użytkownika dopisywał znak !. Należy przetestować wprowadzone zmiany za pomocą narzędzia telnet. Proszę zasymulować połączenie się do powyższego programu dwóch różnych klientów (należy odpalić program telnet dwukrotnie, w różnych terminalach). Co się wtedy dzieje? Zadanie 4Uruchomić powyższy program w środowisku eclipse. Przy użyciu narzędzia telnet przetestować możliwość łączenia się wielu klientów do powyższego programu. Zadanie 5Proszę w parach napisać prosty program typu “chat” do porozumiewania się pomiędzy dwoma użytkownikami.
Protokół TCPProtokół TCP jest jedną z możliwych implementacji warstwy transportu w modelu OSI, ma on następujące cechy:
Pozwala na uwtorzenie dwukierunkowego kanału danych między dwoma hostami w sieci.
Dane wysłane za pomocą protokołu TCP muszą dotrzeć do systemu docelowego. Jeśli nie jest możliwe dostarczenie danych (np. z powodu braku łączności z internetem systemu docelowego) implementacja protokołu TCP musi zwrócić błąd.
Dane wysłane przez protokół TCP posiadają sumy kontrolne, które pozwalają wykryć błędy w transmisji.
Jeśli jakaś wiadomość TCP jest wysłana jako wiele oddzielnych pakietów IP, wiadomość dotrze w tej samej kolejności w jakiej była wysłana. Implementacja TCPNa poziomie protokołu IP operuje się pojedyńczymi pakietami, pakiety te mogą po drodze między dwoma systemami się zawieruszyć. Na poziomie protokolu TCP operuje się strumiueniami danych, strumień tych danych jest niezawodny. W praktyce programowanie oparte na strumieniach (znane z basha) i programowanie TCP nie różni się zbytnio. Pojęcie portuAdresy IP jednoznacznie idenyfikują komputery, my chcielibyśmy jeszcze móc zaadresować kilka usług na jednym komputerze (jest to niemożliwe na poziomie protokołu IP!). Dlatego TCP (oraz UDP) używają dodatkowego numeru zwanego numerem portu. Na komputerze docelowym numer portu jest najczęściej powiązany z usługą z jaką komputer chce się połączyć (port 80 to HTTP) – pełna lista portów dostępna jest w Internecie. Na komputerze inicjującym port jest wybierany losowo. Handshake TCPPołączenie TCP jest jednoznacznie identyfikowane przez cztery liczby:
Numer portu na komputerze do którego jest nawiązywane połączenie.
Numer IP hosta do którego jest nawiązywane połączenie.
Numer portu na komputerze z którego jest nawiązywane połączenie.
Numer IP hosta z którego jest nawiązywane połączenie. By nawiązać połączenie należy wymienić tzw. handshake TCP, polega on na wysłaniu trzech pakietów:
Wysyła go klient, zawiera on losową liczbę x.
Wysyła go serwer, zawiera on losową liczbę y, oraz liczbę x+1.
Wysyła go klient zawiera on liczbę y+1. Narzut TCPUżycie protokółu TCP powoduje powstanie pewnego narzutu (wysyłane są dodatkowe dane, związane z samym protokołem, a nie wysyłaną informacją), którego oszacowanie jest trudne, a sam rozmiar narzutu zależny od rozmiaru poszczególnych pakietów. Dla długich połączeń narzut TCP jest w granicach 5%, dla wysłania pojedyńczej wiadomości może wynosić kilkaset procent (koszt wykonania handshake). Gniazda sieciowe TCP w BASHGniazda siecioweGniazdo (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. 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. Używane opcje:
Możemy sprawdzić ich działanie za pomocą połączenia telnet. Zadanie 1Stworzyć 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. Programowanie gniazd sieciowych w języku JAVANawiązywanie połączeń TCP (klient) Do nawiązywania połączeń TCP służy klasa java.net.Socket. import java.io.*; import java.net.Socket; public class ClientSocket { public static void main(String[] args) throws Exception{ Socket socket = new Socket("google.pl", 80); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bufferedWriter.write("GET / HTTP/1.0\n\n"); bufferedWriter.flush(); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = reader.readLine(); while (line!=null){ System.out.println(line); System.out.flush(); line = reader.readLine(); } } } Ważniejsze części programu: W konstruktorze socketa podajemy adres i port na który się łączymy: Socket socket = new Socket("google.pl", 80); Z socketem powiązane są dwa strumienie, które Państwo znacie z przedmiotu PO Java:
Strumienie te są strumieniami binarnymi (tj. przesyłającymi nie tekst a dane binarne). Ponieważ HTTP jest protokołem tekstowym (w zasadzie) opakowujemy te strumienie do klasy BufferedReader która pozwala wygodnie pracować na tekście: BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); Po wysłaniu linijki danych musimy wykonać polecenie flush które spowoduje wysłanie danych do hosta (implementacja TCP może czekać aż nie zbierze się dostateczna ilość danych by wysłać pełny pakiet: bufferedWriter.flush(); Zadanie 2Uruchomić powyższy program w środowisku eclipse. Następnie, należy połączyć się z serwerem cern.ch na porcie 80. Na ekran należy wypisać tylko te linijki które zawierają słowo body. Przyjmowanie połączeń TCP (serwer)Do tworzenia serwerów w javie służy klasa java.net.ServerSocket. Ten program stworzy serwer odpisujący na to co mu się wysłało: import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class ServerSocketExample { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(12347); while (true){ Socket socket = serverSocket.accept(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bufferedWriter.write("Napisz: \"END\" by zakończyć połączenie."); String line = bufferedReader.readLine(); while (!line.contains("END")){ bufferedWriter.write("Sever says: "); bufferedWriter.write(line); bufferedWriter.write("\n"); bufferedWriter.flush(); line = bufferedReader.readLine(); } socket.close(); } } } Ciekawsze elementy programu: Tworzymy serwer który będzie akceptował połączenia na porcie 12347: ServerSocket serverSocket = new ServerSocket(12347); Wywołanie serverSocket.accept() jest blokujące tj. metoda ta zakończy się w momencie w którym serwer otrzyma połączenie. Metoda ta zwraca zwykłego socketa pozwalającego odczytywać i zapisywać dane do zdalnego systemu. Zadanie 3Uruchomić powyższy program w środowisku eclipse. Przerobić program w taki sposób, by do tekstu wysyłanego przez użytkownika dopisywał znak !. Należy przetestować wprowadzone zmiany za pomocą narzędzia telnet. Proszę zasymulować połączenie się do powyższego programu dwóch różnych klientów (należy odpalić program telnet dwukrotnie, w różnych terminalach). Co się wtedy dzieje? Wielowątkowy serwer w JavieSerwer z poprzedniego przykładu jest jednowątkowy, tj. kiedy obsługuje jednego klienta i nie akceptuje połączeń od innych klientów. Oczywiście jest to niepożądana cecha, w praktyce serwery oprogramowuje się tak by każde połączenie było oprogramowane w oddzielnym wątku. Ponższy przykład jest w stanie obsłużyć wiele wątków:
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MultihreadedServerSocketExample { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(12347); ExecutorService executorService = Executors.newFixedThreadPool(10); while (true){ final Socket socket = serverSocket.accept(); Runnable connection = new Runnable() { @Override public void run() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bufferedWriter.write("Napisz: \"END\" by zakończyć połączenie."); bufferedWriter.flush(); String line = bufferedReader.readLine(); while (!line.contains("END")){ bufferedWriter.write("Sever says: "); bufferedWriter.write(line); bufferedWriter.write("\n"); bufferedWriter.flush(); line = bufferedReader.readLine(); } socket.close(); } catch (IOException e) { e.printStackTrace(); } } }; executorService.submit(connection); } } }
Informacje na temat przykładu: Żeby socket był widoczny wewnątrz instancji Runnable musimy poprzedzić go modyfikatorem final. Pojawił się ExecutorService Połączenie obsługiwane jest nie w wątku main a w wątku zarządzanym przez ExecutorService. Musimy obsłużyć błędy w połączeniu, bo interfejs Runnable nie pozwala na propagację wyjątków z metody run. Zadanie 4Uruchomić powyższy program w środowisku eclipse. Przy użyciu narzędzia telnet przetestować możliwość łączenia się wielu klientów do powyższego programu. Następnie podłączyć się do uruchomionego serwera kolegi używając narzędzia telnet. Zadanie 5Proszę w parach napisać prosty program typu “chat” do porozumiewania się pomiędzy dwoma użytkownikami.
Scanner sc = new Scanner(System.in); sc.nextLine(); UWAGA:
|