Wykorzystano fragmenty wykładów M. Piotrowskiego i M. Wójcika K O M U N I K A C J A MIĘDZYPROCESOWA O B S Ł U G A WEJŚCIA/WYJŚCIA Waldemar Korłub Platformy Technologiczne KASK ETI Politechnika Gdańska
Komunikacja międzyprocesowa 2 Podstawowe metody wymiany informacji między aplikacjami/procesami obejmują: Pliki Potoki nienazwane (ang. pipe) np. połączone z stdin/stdout/stderr Gniazda (ang. sockets) Oraz protokoły budowane na ich podstawie, np. HTTP Java oferuje zunifikowany model strumieni wejścia/wejścia do obsługi wielu źródeł danych ang. I/O streams nie mylić z API Stream
Strumienie wejścia/wyjścia 3 Strumienie bajtowe (ang. Byte Streams) odczyt/zapis bajtów InputStream (np. FileInputStream, AudioInputStream) OutputStream (np. FileOutputStream, ByteArrayOutputStream) Strumienie znakowe (ang. Character Streams) odczyt/zapis znaków Reader (np. FileReader, InputStreamReader), Writer Wykorzystują zestaw znaków Unicode do przechowywania znaków Automatyczna translacja znaków pomiędzy Unicode a lokalnym zbiorem znaków
Strumienie wejścia/wyjścia 4 Strumienie należy zamykać (metoda close()) po zakończeniu pracy z nimi Strumień może być powiązany z otwartym plikiem na dysku, gniazdem sieciowym itd. Brak zamknięcia strumienia skutkuje wiszącym połączeniem sieciowym, zablokowanym plikiem na dysku Nie należy polegać w tej kwestii na mechanizmie garbage collector Nie ma gwarancji co do momentu uruchomienia GC Nie ma gwarancji co do wywołania finalizatorów np. awaria aplikacji, zabicie procesu (SIGKILL) Zalecana konstrukcja try-with-resources (przykład w dalszej części)
Buforowanie 5 Poprawia wydajność komunikacji za pośrednictwem strumieni wejścia/wyjścia Redukcja liczby odwołań do pliku na dysku/gniazda sieciowego Byte Streams BufferedInputStream BufferedOutputStream Character Streams BufferedReader BufferedWriter Dekoratory dla podstawowych strumieni bajtowych i znakowych Metoda flush() wymusza zapisanie zawartości bufora
Dekorowanie strumieni 6 Podstawowy strumień: InputStream input = /*...*/; Z buforowaniem: BufferedInputStream buffered = new BufferedInputStream(input); Z buforowaniem i dekompresją: GZIPInputStream gzipstream = new GZIPInputStream(buffered); Z deserializacją obiektów: ObjectInputStream objectstream = new ObjectInputStream(gzipStream);
Strumień serializowanych obiektów 7 Java umożliwia binarną serializację obiektów W celu ich zapisu do pliku na dysku W celu ich przesłania przez sieć do innej aplikacji Binarna serializacja daje większą wydajność niż w przypadku użycia formatów tekstowych takich, jak JSON/XML/YAML ale wymaga Javy po stronie zapisującej oraz po stronie odczytującej
Serializacja 8 Klasy możliwe do zserializowania oznacza się interfejsem Serializable Interfejs znakujący nie posiada żadnych metod Wybrane pola klasy można pominąć w czasie serializacji modyfikator transient Różne wersje klasy można oznaczyć identyfikatorami: static final long serialversionuid = 17;
Serializacja strumienie obiektów 9 ObjectOutputStream: ObjectOutputStream objectout =... objectout.writeutf("imiesław"); objectout.writeint(20); Serializable dev = new Developer(); objectout.writeobject(dev); ObjectInputStream: ObjectInputStream objectin =... String name = objectin.readutf(); int age = objectin.readint(); Developer dev = (Developer) objectin.readobject();
Standardowe strumienie 10 stdin: System.in (InputStream) stdout: System.out (PrintStream) stderr: System.err (PrintStream)
11 Pliki i katalogi
Klasa File 12 Przed Javą SE7 podstawowa klasa do operacji na drzewie plików i katalogów Obiekty klasy File reprezentują zarówno pliki jak i katalogi W duchu UNIXowej idei: wszystko jest plikiem Udostępnia podstawowe informacje na temat elementów na dysku
Klasa File 13 Pozyskanie instancji: String path = "..."; File file = new File(path); Sprawdzenie typu: boolean isdirectory = file.isdirectory(); boolean isfile = file.isfile(); Czas modyfikacji: long lastmodifiedms = file.lastmodified(); Date lastmodified = new Date(lastModifiedMS); Zawartość katalogu (jeśli jest katalogiem, w przeciwnym razie null): File[] files = file.listfiles();
Wady klasy File 14 Wiele metod nie rzuca wyjątku w razie niepowodzenia np. boolean File.delete() Problemy z przenośnością metody rename() Brak obsługi dowiązań symbolicznych Ograniczony dostęp do metadanych np. właściciel pliku Problemy ze skalowalnością np. listowanie zawartości katalogu o dużej liczbie elementów
java.nio.files.* Path oraz Files 15 Nowe klasy narzędziowe wprowadzone w SE7 Rozwiązują problemy występujące w klasie File Path i Files zalecane do użycia w nowych projektach Path Reprezentuje lokalizację pliku/katalogu na dysku Z uwzględnieniem specyfiki systemu operacyjnego Paths.get("katalog", "plik.txt"); Implementuje interfejs Watchable Możliwość nasłuchiwania na zmiany, np. dodanie pliku w katalogu, usunięcie pliku, modyfikacja pliku Files Klasa narzędziowa oferująca metody statyczne do operacji na obiektach Path
Path i Files 16 Pozyskanie instancji: Path p = Paths.get("katalog", "plik.txt"); Sprawdzenie typu: boolean isdirectory = Files.isDirectory(p); boolean isfile = Files.isRegularFile(p); Zawartość katalogu: Stream<Path> paths = Files.list(p); Odroczone ładowanie (ang. lazily populated) rozwiązuje problem wydajności listowania dużych katalogów Usuwanie: Files.delete(p); Wyrzuca IOException w razie niepowodzenia
try-with-resources 17 Dysponując obiektem File/Path można otworzyć strumienie do wczytywania i zapisywania plików Strumienie należy zamykać po zakończeniu pracy z nimi W przeciwnym razie pozostaje wiszący uchwyt pliku/wiszące połączenie socketowe itd. Składnia try-with-resources umożliwia automatyczne zamykanie strumieni i innych zasobów Muszą implementować interfejs AutoCloseable
try-with-resources 18 Automatyczne zamykanie strumienia: try (BufferedReader reader = Files.newBufferedReader(path)) { String line = reader.readline(); //...przetwarzanie... } //automatyczne zamknięcie strumienia
19 Gniazda
Gniazdo (ang. socket) 20 Punkt końcowy w dwukierunkowej komunikacji pomiędzy dwoma programami działającymi w sieci (lub na lokalnym komputerze) Powiązane z konkretnym portem (1-65535) Serwer nasłuchuj na połączenia od klientów na określonym porcie Aplikacje klienckie łącząc się z serwerem specyfikują port Na jednym komputerze wiele aplikacji może równocześnie nasłuchiwać na różnych portach
Połączenia 21 TCP Transmission Control Protocol Połączeniowy Retransmisje Zachowana kolejność Potwierdzenia Wiarygodny UDP User Datagram Protocol Bezpołączeniowy Brak retransmisji Kolejność niezapewniona Brak potwierdzeń Niewiarygodny
Połączenia 22 Klasy umożliwiające połączenia: TCP (Transmission Control Protocol): URL URLConnection Socket ServerSocket UDP (User Datagram Protocol): DatagramPacket DatagramSocket MulticastSocket
Połączenie TCP 23 Serwer Nasłuchiwanie na wybranym porcie: new ServerSocket(int port) Akceptowanie połączenia z klientem (metoda blokująca): Socket ServerSocket.accept() Klient Połączenie z wybranym hostem na określonym porcie: new Socket(String host, int port) Obie strony OutputStream Socket.getOutputStream() InputStream Socket.getInputStream()
try-with-resources 24 Automatyczne zamykanie strumieni: Socket socket = new Socket("192.168.1.17", 1337); try(bufferedreader reader = Files.newBufferedReader(path); OutputStream output = socket.getoutputstream()) { String line = reader.readline(); //...przetwarzanie... output.write(/*...*/); } //automatyczne zamknięcie obu strumieni
Datagramy UDP 25 Niezależne, samodzielne wiadomości przesyłane przez sieć Brak gwarancji co do faktu dostarczenia, czasu dostarczenia czy integralności treści Główne klasy: DatagramSocket gniazdo datagramowe DatagramPacket pojedynczy pakiet MulticastSocket odbieranie pakietów wysłanych do grupy hostów InetAddress reprezentacja adresu protokołu IP
Przesyłanie datagramu 26 Serwer: Rozpoczęcie nasłuchiwania na określonym porcie: new DatagramSocket(int port) Odbieranie pakietu (blokujące): void DatagramSocket.receive(DatagramPacket p) Klient: Pozyskanie instancji gniazda: new DatagramSocket(); Nie wymaga adresu hosta ani portu adres w datagramie Konstrukcja pakietu datagramowego: new DatagramPacket(byte[] buff, int length, InetAddress address, int port), Wysyłanie pakietu: void DatagramSocket.send(DatagramPacket packet)
Multicast 27 Nadawca: Wysyłanie za pomocą DatagramSocket Konstrukcja adresu multicast (w zależności od maski podsieci): InetAddress.getByName("192.168.0.63") Odbiorcy: Rozpoczęcie nasłuchiwania na określonym porcie: new MulticastSocket(int port) Dołączenie do grupy multicast: MulticastSocket.joinGroup(InetAddress group) Host może być podłączony do kilku sieci Opuszczenie grupy: MulticastSocket.leaveGroup(InetAddress group) Odebranie pakietu: void MulticastSocket.receive(DatagramPacket p)
28 Pytania?