Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00260 005959 14496783 na godz. na dobę w sumie
Java. Ćwiczenia zaawansowane. Wydanie II - książka
Java. Ćwiczenia zaawansowane. Wydanie II - książka
Autor: Liczba stron: 176
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-3497-2 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> java - programowanie
Porównaj ceny (książka, ebook (-30%), audiobook).

Mistrzostwo w Javie w zasięgu Twoich rąk!

Rzadko zdarza się, by jeden język programowania był w stanie zaspokoić niemal wszystkie potrzeby obsługi bardzo różnych urządzeń i systemów operacyjnych bez konieczności żmudnego dostosowywania. Java znakomicie spełnia te wymagania i właśnie dlatego każdy programista - nawet taki, który używa w swojej pracy innych języków programowania - powinien poznać ją bardzo dokładnie. A najłatwiejszym i najbardziej efektywnym sposobem poszerzenia wiedzy w dziedzinie programowania jest przećwiczenie rozmaitych przypadków konkretnych zastosowań danego języka. Jeśli zetknąłeś się już kiedyś z Javą, dobrze znasz jej podstawy, lecz zależy Ci na opanowaniu szerszego spektrum możliwości, powinieneś koniecznie sięgnąć po książkę 'Java. Ćwiczenia zaawansowane. Wydanie II'.

Znajdziesz tu zestaw niemal stu ćwiczeń pomagających zrozumieć takie zagadnienia, jak programowanie współbieżne i obsługa wątków, budowanie aplikacji wielowątkowych z interfejsem graficznym, nawiązywanie połączeń sieciowych, komunikacja sieciowa z użyciem protokołu wymiany danych, serwery wielowątkowe, współpraca z relacyjnymi bazami danych czy obsługa zapytań SQL. Nauczysz się uruchamiać, przerywać i synchronizować wątki oraz poznasz sposób działania gniazd w Javie i gniazd serwerowych. Dowiesz się więcej o przesyłaniu danych w sieci, serwerach wielowątkowych i sterowaniu serwerem z konsoli. Zobaczysz, jak powinno wyglądać budowanie aplikacji sieciowych z interfejsem graficznym w Javie oraz o czym koniecznie trzeba pamiętać. Ponadto jasne staną się dla Ciebie wszystkie tajniki komunikacji z bazą danych oraz sposób obsługi zapytań w SQL.

Błyskawicznie opanuj nowe umiejętności i zaimponuj klientom!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Redaktor prowadzący: Ewelina Burska Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 032 231 22 19, 032 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie?czjav2 Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Kody źródłowe wszystkich opublikowanych listingów można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/czjav2.zip ISBN: 978-83-246-3497-2 Copyright © Helion 2012 Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treĂci WstÚp Rozdziaï 1. Programowanie wspóïbieĝne WÈtki i klasa Thread Interfejs Runnable Przerywanie pracy wÈtku WÈtki w aplikacjach okienkowych Rozdziaï 2. Synchronizacja wÈtków Modyfikacja wspólnych danych Synchronizacja za pomocÈ sïowa kluczowego synchronized Nowe moĝliwoĂci synchronizacji Rozdziaï 3. Programowanie sieciowe Rozdziaï 4. Mechanizm gniazd Gniazda w Javie Gniazda serwerowe Transmisja danych w modelu klient – serwer Przesyïanie danych w sieci Serwer wielowÈtkowy Sterowanie serwerem z konsoli Rozdziaï 5. Aplikacje sieciowe z interfejsem graficznym Budowa interfejsu Obsïuga interfejsu i procedury komunikacyjne Tworzenie serwera Obsïuga protokoïu komunikacyjnego 5 7 7 12 17 20 25 25 28 34 43 43 44 51 57 57 70 74 85 85 91 102 107 4 Java • mwiczenia zaawansowane Rozdziaï 6. Wspóïpraca z bazami danych NawiÈzywanie poïÈczeñ Wykonywanie zapytañ pobierajÈcych dane Dodawanie i modyfikacja rekordów Obsïuga róĝnych typów zapytañ Obsïuga transakcji 117 117 122 133 140 144 3 Programowanie sieciowe Mechanizm gniazd Mechanizm gniazd jest znany wiÚkszoĂci programistów, jednak dla tych czytelni- ków, którzy siÚ z nim nie zetknÚli, krótkie wyjaĂnienie. Gniazda (ang. sockets) jest to mechanizm komunikacyjny, umoĝliwiajÈcy transmi- sjÚ danych pomiÚdzy urzÈdzeniami w sieci opartej na protokole IP. Obecnie jest to mechanizm powszechnie stosowany w komunikacji sieciowej. Gniazda moĝna traktowaÊ jako koñcówki poïÈczeñ znajdujÈce siÚ w komputerach (ogólniej: urzÈ- dzeniach sieciowych). StÈd teĝ pochodzi nazwa „gniazdo” — czyli coĂ, do czego moĝ- na wïoĝyÊ wtyczkÚ. OczywiĂcie w tym przypadku chodzi o wtyczkÚ wirtualnÈ. Po utworzeniu gniazda moĝna uĝywaÊ go do komunikacji z innym komputerem bÈdě teĝ urzÈdzeniem sieciowym. Dane wysïane do gniazda bÚdÈ przesyïane do urzÈ- dzenia, z którym zostaïo nawiÈzane poïÈczenie. Transmisja jest oczywiĂcie dwukie- runkowa, zatem dane odsyïane przez odlegïe urzÈdzenie sieciowe moĝna rów- nieĝ odbieraÊ z gniazda. Jest to zatem swego rodzaju punkt komunikacyjny. Aby poïÈczyÊ siÚ z odlegïym komputerem, niezbÚdne jest okreĂlenie dwóch warto- Ăci. Po pierwsze — jego adresu sieciowego IP, po drugie — numeru portu. Czym jest numer portu? Otóĝ na kaĝdym komputerze moĝe dziaïaÊ wiele usïug, np. serwer WWW, poczty czy FTP. Trzeba zatem zakomunikowaÊ, z jakÈ usïugÈ (aplikacjÈ, procesem) ma nastÈpiÊ poïÈczenie. Numer portu jest wïaĂnie takim identyfikato- rem. Liczba dostÚpnych portów jest zaleĝna od rodzaju i wersji systemu opera- cyjnego. Jednak niezaleĝnie od tego, ile ich oferuje system, dla typowych protokoïów transmisyjnych TCP i UDP moĝna uĝyÊ co najwyĝej 65 535 portów1, numerowanych od 1 do 65 535 (port zerowy nie jest uĝywany do transmisji danych). Zatem teoretycznie 1 Wynika to z tego, ĝe w nagïówkach segmentów danych TCP i UDP na numer portu zarezerwowane jest 16 bitów. 44 Java • mwiczenia zaawansowane dla jednego adresu IP tyle wïaĂnie róĝnych usïug i serwisów moĝna zaoferowaÊ (w praktyce liczba ta bÚdzie mniejsza, gdyĝ czÚĂÊ portów jest zarezerwowana, a po- jedyncza usïuga moĝe teĝ korzystaÊ z wielu z nich). Gniazda z reguïy dzielimy na strumieniowe — umoĝliwiajÈce transmisjÚ strumienio- wÈ (np. TCP), datagramowe — umoĝliwiajÈce transmisjÚ pakietowÈ (np. UDP) oraz tzw. raw sockets — pozwalajÈce na bezpoĂrednie wysyïanie pakietów (ramek) IP z pominiÚciem narzutu protokoïów wyĝszych warstw sieciowych (spotykane tïuma- czenie nazwy to „gniazda surowe”). W dalszej czÚĂci rozdziaïu bÚdzie poruszany jedynie temat gniazd strumieniowych. Gniazda w Javie W Javie dostÚpne sÈ gniazda sïuĝÈce do komunikacji sieciowej. Ten, kto progra- mowaï „czyste” gniazda, np. pod Uniksem, bÚdzie jednak z pewnoĂciÈ mile zasko- czony, gdyĝ mechanizmy te w przypadku Javy sÈ o wiele bardziej przyjazne uĝyt- kownikowi. Odpowiednie klasy znajdujÈ siÚ w pakiecie java.net. Do dyspozycji sÈ gniazda klienckie (ang. client socket) i serwerowe (ang. server socket), zarówno strumieniowe, jak i datagramowe. Do komunikacji wykorzystywany jest protokóï IP. Gniazda klienckie strumieniowe reprezentowane sÈ przez klasÚ Socket, która udo- stÚpnia konstruktory przedstawione w tabeli 3.1. Tabela 3.1. Konstruktory klasy Socket Konstruktor Socket() Socket(InetAddress address, int port) Socket(InetAddress address, int port, InetAddress localAddr, int localPort) Socket(Proxy proxy) Socket(SocketImpl impl) Socket(String host, int port) Socket(String host, int port, InetAddress localAddr, int localPort) Opis Tworzy gniazdo niepoïÈczone z ĝadnym adresem. Tworzy nowe gniazdo podïÈczone do adresu address i portu port. Tworzy nowe gniazdo podïÈczone do adresu address i portu port oraz do lokalnego adresu localAddr i lokalnego portu localPort. Tworzy nowe gniazdo, uĝywajÈce do komunikacji serwera poĂredniczÈcego proxy wskazanego przez argument proxy. Konstruktor dostÚpny od wersji JDK 1.5. Tworzy nowe gniazdo niepodïÈczone do ĝadnego adresu, o implementacji zadanej przez uĝytkownika. Tworzy nowe gniazdo podïÈczone do adresu wskazanego przez ciÈg znaków host oraz portu wskazanego przez argument port. Tworzy nowe gniazdo podïÈczone do komputera host i portu port oraz do lokalnego adresu localAddr i lokalnego portu localPort. Rozdziaï 3. • Programowanie sieciowe 45 Oprócz konstruktorów wymienionych w tabeli 3.1 dostÚpne sÈ jeszcze dwa inne: Socket(InetAddress host, int port, boolean stream) i Socket(String host, int port, boolean stream), sÈ one jednak przestarzaïe i nie naleĝy ich stosowaÊ (zostaïy zachowane jedynie w celu zachowania zgodnoĂci z wczeĂniejszymi JDK). ZawierajÈ bowiem argument stream wskazujÈcy, czy gniazdo ma byÊ strumieniowe, czy datagra- mowe, a obecnie dla gniazd datagramowych naleĝy stosowaÊ klasÚ DatagramSocket. Przy tworzeniu obiektów typu Socket, w zaleĝnoĂci od uĝytego konstruktora, mogÈ zostaÊ zgïoszone nastÚpujÈce wyjÈtki: T IOException — gdy wystÈpiï bïÈd wejĂcia-wyjĂcia, T UnknownHostException — gdy nie moĝna uzyskaÊ adresu IP wskazanego hosta, T SecurityException — gdy brak wystarczajÈcych uprawnieñ do utworzenia T IllegalArgumentException — gdy argument port zawiera wartoĂÊ spoza dopuszczalnego zakresu (0 – 65535), gniazda, null). T NullPointerException — gdy argument wskazujÈcy adres jest pusty (ma wartoĂÊ Spróbujmy zatem utworzyÊ obiekt typu Socket poïÈczony z wybranym adresem zdalnym. m W I C Z E N I E 3.1 Tworzenie gniazda Napisz program tworzÈcy gniazdo strumieniowe poïÈczone z wybranym adresem i portem zdalnym. WyĂwietl informacje o poïÈczeniu na ekranie. import java.net.*; import java.io.*; public class Main { public static void main(String args[]) { Socket socket = null; try{ socket = new Socket( helion.pl , 80); } catch(UnknownHostException e){ System.out.println(e); } catch(IOException e){ System.out.println(e); } if(socket != null){ System.out.println(socket); } } } 46 Java • mwiczenia zaawansowane Na poczÈtku kodu importowane sÈ pakiety java.net (do obsïugi gniazd) oraz java.io (ze wzglÚdu na obsïugÚ wyjÈtku IOException). W klasie Main znajduje siÚ zmienna socket typu Socket, której poczÈtkowÈ wartoĂciÈ jest null. W bloku try nastÚpuje próba utworzenia nowego obiektu typu Socket i przypisania odniesienia do niego tej wïa- Ănie zmiennej. W konstruktorze przekazywany jest adres hosta, z którym ma na- stÈpiÊ poïÈczenie (helion.pl) oraz numer portu (80 — standardowy port protokoïu HTTP). Poniewaĝ konstruktor moĝe zgïosiÊ róĝne wyjÈtki, zostaïy równieĝ uĝyte dwa bloki catch, aczkolwiek jedynÈ czynnoĂciÈ w nich wykonywanÈ jest wyĂwietla- nie danych obiektu wyjÈtku. W praktyce moĝna oczywiĂcie zróĝnicowaÊ sposób reakcji na bïÈd w zaleĝnoĂci od jego typu. Na zakoñczenie wyĂwietlane sÈ dane obiektu socket, o ile taki obiekt udaïo siÚ utworzyÊ, czyli gdy zmienna socket jest róĝna od null. Po skompilowaniu i uruchomieniu programu na ekranie powinien pojawiÊ siÚ widok zaprezentowany na rysunku 3.1. Dostarczone zostanÈ informacje o adresie do- menowym, adresie IP, numerze portu zdalnego oraz numerze portu lokalnego. Warto teĝ zmieniÊ w kodzie adres lub port, z którym ma nastÈpiÊ poïÈczenie, na nieprawi- dïowy, po czym ponownie skompilowaÊ i uruchomiÊ aplikacjÚ. ZostanÈ wtedy wyĂwietlone informacje o obiekcie wyjÈtku, np. takie jak na rysunku 3.2. Rysunek 3.1. Informacje o nawiÈzanym poïÈczeniu Rysunek 3.2. Komunikaty o bïÚdach zwiÈzanych z niewïaĂciwymi danymi Rozdziaï 3. • Programowanie sieciowe 47 W tabeli 3.1 widaÊ, ĝe niektóre z konstruktorów klasy Socket przyjmujÈ adresy hostów w postaci obiektów klasy InetAddress. Obiektów tego typu nie tworzy siÚ bezpo- Ărednio, ale korzystajÈc z metod statycznych tej klasy. Oprócz nich do dyspozycji jest takĝe kilka innych metod pozwalajÈcych uzyskiwaÊ informacje dotyczÈce adresów internetowych. Wybrane metody udostÚpniane przez InetAddress zostaïy przedstawio- ne w tabeli 3.2. Tabela 3.2. Wybrane metody klasy InetAddress Typ zwracany byte[] static InetAddress[] static InetAddress Metoda getAddress() getAllByName(String host) getByAddress(byte[] addr) static InetAddress getByAddress(String host, byte[] addr) Opis Zwraca adres IP w postaci tablicy bajtów. Zwraca wszystkie adresy IP urzÈdzenia okreĂlonego przez argument host. Zwraca obiekt typu InetAddress, odpowiadajÈcy adresowi IP przekazanemu w postaci tablicy bajtów addr. Zwraca obiekt typu InetAddress, odpowiadajÈcy adresowi IP przekazanemu w postaci tablicy bajtów addr i nazwie okreĂlonej przez argument host. static InetAddress getByName(String host) Ustala adres IP urzÈdzenia okreĂlonego przez argument host. getCanonicalHostName() Zwraca kwalifikowanÈ nazwÚ domenowÈ dla getHostAddress() getHostName() danego adresu IP. Zwraca adres IP w postaci ciÈgu znaków. Zwraca nazwÚ hosta dla danego adresu IP. Ustala adres IP komputera lokalnego. getLocalHost() getLoopbackAddress() Ustala adres IP pÚtli lokalnej (ang. loopback isMulticastAddress() isReachable(int timeout) address). Metoda dostÚpna od JDK 1.7. Sprawdza, czy dany adres jest adresem typu multicast. Sprawdza, czy dany host jest osiÈgalny w sieci. Argument timeout okreĂla (w milisekundach) maksymalny czas badania. String String String static InetAddress static InetAddress boolean boolean boolean String isSiteLocalAddress() Sprawdza, czy adres jest adresem lokalnym. toString() Dokonuje konwersji adresu na ciÈg znaków. WykorzystujÈc dane przedstawione w tabeli 3.2, moĝna w prosty sposób napisaÊ program wyĂwietlajÈcy adres IP komputera, na którym zostaï uruchomiony. Wy- starczy uĝyÊ metody getLocalHost. 48 m W I C Z E N I E 3.2 Java • mwiczenia zaawansowane Uzyskiwanie lokalnego adresu IP import java.net.*; public class Main { public static void main(String args[]) { InetAddress inetAddress = null; try{ inetAddress = InetAddress.getLocalHost(); } catch(UnknownHostException e){ System.out.println( Nie moľna uzyskaè adresu IP dla tego komputera. ); System.exit(0); } String ip = inetAddress.getHostAddress(); System.out.println( Adres IP tego komputera to: + ip); } } Najpierw zostaïa utworzona zmienna inetAddress typu InetAddress, a nastÚpnie w blo- ku try nastÈpiïo wywoïanie statycznej metody getLocalHost klasy InetAddress. Metoda ta zwraca obiekt zawierajÈcy adres IP komputera lokalnego (na którym zostaï uruchomio- ny program). Blok try jest konieczny, jako ĝe przy wywoïaniu getLocalHost moĝe wystÈpiÊ wyjÈtek UnknownHostException. BÚdzie tak w sytuacji, gdy pobranie adresu nie jest moĝliwe. Ewentualny wyjÈtek jest obsïugiwany w bloku catch (wyĂwietlany jest stosowny komunikat i program koñczy dziaïanie). Uzyskany adres IP, zawarty w obiekcie inetAddress, jest uzyskiwany za pomocÈ metody getHostAddress (która zwró- ci go w postaci ciÈgu znaków — obiektu typu String) oraz wyĂwietlany na ekranie. Skoro moĝliwe jest pobranie adresu IP komputera lokalnego, na pewno moĝna teĝ pobraÊ adres dowolnego urzÈdzenia w sieci. W tym celu wystarczy uĝyÊ metody getByName klasy InetAddress i przekazaÊ jej nazwÚ domenowÈ. Zwrócony obiekt bÚdzie zawieraï poszukiwane dane, o ile oczywiĂcie wywoïanie metody zakoñczy siÚ sukcesem. Jeĝeli adresu nie uda siÚ pobraÊ, wygenerowany zostanie wyjÈtek UnknownHostException. Warto zatem napisaÊ program, któremu w wierszu poleceñ bÚdzie przekazywana nazwa domenowa, a w odpowiedzi na ekranie pojawi siÚ od- powiadajÈcy jej adres IP (o ile taki istnieje). Rozdziaï 3. • Programowanie sieciowe 49 m W I C Z E N I E 3.3 Pobieranie dowolnego adresu IP Napisz program, który bÚdzie podawaï adres IP komputera (urzÈdzenia sieciowego) o nazwie domenowej przekazanej z wiersza poleceñ. import java.net.*; public class Main { public static void main(String args[]) { if (args.length 1){ System.out.println( Wywođanie programu: Main nazwa_hosta ); System.exit(0); } String host = args[0]; InetAddress inetAddress = null; try{ inetAddress = InetAddress.getByName(host); } catch(UnknownHostException e){ System.out.println( Nie moľna uzyskaè adresu IP dla hosta + host); System.exit(0); } String ip = inetAddress.getHostAddress(); System.out.println( Adres IP komputera + host + to: + ip); } } PierwszÈ wykonywanÈ czynnoĂciÈ jest sprawdzenie liczby elementów tablicy args przekazanej metodzie main. Jeĝeli wartoĂÊ wïaĂciwoĂci length jest mniejsza od 1, oznacza to, ĝe w wywoïaniu programu nie zostaï podany ĝaden argument. W takiej sytuacji jedynÈ wykonywanÈ czynnoĂciÈ jest wyĂwietlenie komunikatu z informacjÈ o prawidïowym sposobie wywoïania i program koñczy dziaïanie (wywoïanie sta- tycznej metody exit z klasy System). Jeĝeli jednak aplikacja zostaïa uruchomiona z co najmniej jednym argumentem (czyli liczba elementów tablicy lenght jest wiÚksza od 0), pierwszy argument (o in- deksie 0) jest przypisywany pomocniczej zmiennej host, powstaje takĝe zmienna inetAddress typu InetAddress. WartoĂÊ zapisana w host jest uĝywana w wywoïaniu statycznej metody getByName klasy InetAddress, a rezultat dziaïania getByName (obiekt zawierajÈcy dane dotyczÈce adresu internetowego, w tym poszukiwany adres IP) jest przypisywany zmiennej inetAddress. Wywoïanie metody getByName jest ujÚte w blok try…catch, jako ĝe w przypadku niemoĝnoĂci ustalenia adresu jest generowany wyjÈtek UnknownHostException. JeĂli tak siÚ stanie, na ekranie pojawi siÚ odpowiedni komunikat. Jeĝeli jednak adres da siÚ uzyskaÊ, zostanie on pobrany za pomocÈ metody getHostAddress i równieĝ wy- Ăwietlony na ekranie. 50 Java • mwiczenia zaawansowane mwiczenie 3.3 pokazaïo, jak uzyskaÊ adres IP dowolnego hosta w sieci. Jednak do jed- nego adresu domenowego moĝe byÊ przypisanych wiele adresów IP. Wszystkie mogÈ byÊ odczytane za pomocÈ metody getAllByName. Rezultatem jej dziaïania jest tablica obiektów typu InetAddress. m W I C Z E N I E 3.4 Pobranie wszystkich adresów przypisanych do wybranego hosta Napisz program, który wyĂwietli wszystkie adresy IP przypisane do urzÈdzenia sieciowego o nazwie przekazanej w postaci argumentu w wierszu poleceñ. import java.net.*; public class Main { public static void main(String args[]) { if (args.length 1){ System.out.println( Wywođanie programu: Main nazwa_hosta ); System.exit(0); } InetAddress ips[] = null; String hostName = args[0]; try{ ips = InetAddress.getAllByName(hostName); } catch(UnknownHostException e){ System.out.println( Nie moľna uzyskaè adresów IP dla komputera: + hostName); System.exit(0); } System.out.println( Uzyskane adresy IP to: ); for (int i = 0; i ips.length; i++){ String ip = ips[i].getHostAddress(); System.out.println( IP[ + i + ] = + ip); } } } PoczÈtek kodu jest taki sam jak w Êwiczeniu 3.3. Potem nastÚpuje badanie, czy z wiersza poleceñ zostaï przekazany parametr okreĂlajÈcy nazwÚ hosta. Dalej dekla- rowana jest zmienna tablicowa ips o poczÈtkowej wartoĂci null. W bloku try zmiennej tej przypisywany jest wynik dziaïania statycznej metody getAllByName klasy InetAddress. Jeĝeli ta operacja zakoñczy siÚ sukcesem, w tablicy ips znajdÈ siÚ wszystkie adresy hosta okreĂlonego przez zmiennÈ pomocniczÈ hostName (zmienna ta zawiera ciÈg znaków przekazany jako argument z wiersza poleceñ). JeĂli nato- miast adresów nie uda siÚ pobraÊ, jest generowany wyjÈtek przechwytywany na- stÚpnie przez blok catch. Rozdziaï 3. • Programowanie sieciowe 51 ZawartoĂÊ tablicy ips jest odczytywana w pÚtli typu for. Adres IP uzyskuje siÚ przez wywoïanie metody getHostAddress — rezultat jej dziaïania jest przypisywany zmiennej pomocniczej ip. WartoĂÊ zapisana w ip jest nastÚpnie wyĂwietlana na ekranie. Wynik przykïadowego wywoïania aplikacji zostaï przedstawiony na ry- sunku 3.3. Rysunek 3.3. Odczytanie adresów IP przypisanych nazwie domenowej google.pl Gniazda serwerowe Do tej pory zostaïy przedstawione jedynie gniazda klienckie (ang. client sockets). PozwalajÈ one jedynie na pisanie programów ïÈczÈcych siÚ z dziaïajÈcymi serwe- rami. Jeĝeli jednak chcemy samodzielnie napisaÊ program serwera, musimy skorzy- staÊ z gniazd serwerowych (ang. server sockets). Gniazda takiego typu nasïuchujÈ na wskazanym porcie i kiedy nadejdzie poïÈczenie, tworzÈ dla niego gniazdo klienc- kie, sïuĝÈce do dalszej komunikacji. Gniazda serwerowe w Javie sÈ zaimplementowane przez klasÚ ServerSocket. Oferuje ona konstruktory przedstawione w tabeli 3.3. Tabela 3.3. Konstruktory klasy ServerSocket Konstruktor ServerSocket() Opis Tworzy niepowiÈzane (nieprzypisane) gniazdo serwerowe. ServerSocket(int port) Tworzy gniazdo serwerowe nasïuchujÈce na porcie port. ServerSocket(int port, int backlog) Tworzy gniazdo serwerowe nasïuchujÈce na porcie port, z kolejkÈ wejĂciowÈ o dïugoĂci wskazanej przez argument backlog. ServerSocket(int port, int backlog, InetAddress bindAddr) Tworzy gniazdo serwerowe nasïuchujÈce na porcie port, z kolejkÈ wejĂciowÈ o dïugoĂci backlog, przypisane do adresu (powiÈzane z adresem) bindAddr. 52 Java • mwiczenia zaawansowane Argument port moĝe okreĂlaÊ konkretny numer portu (od 1 do 65535) lub teĝ przy- jÈÊ wartoĂÊ 0. W tym drugim przypadku system sam przydzieli wolny numer. Ta opcja jest uĝyteczna, gdyĝ dziÚki niej nie trzeba rÚcznie sprawdzaÊ, który port jest akurat wolny, jednak uniemoĝliwia przypisanie serwerowi (gniazdu serwera) wy- branego numeru portu. Argument backlog pozwala na ustalenie wielkoĂci kolejki wejĂciowej. Jego dokïadne znaczenie jest uzaleĝnione od konkretnej implementacji Javy i systemu operacyjnego. Jeĝeli podczas obsïugi jednego zgïoszenia na dany port przychodzi kolejne wywoïa- nie, zostaje ono ustawione w kolejce wejĂciowej. JeĂli wielkoĂÊ tej kolejki przekro- czy wartoĂÊ podanÈ jako backlog, wywoïanie to zostanie odrzucone. Podanie warto- Ăci 0 (lub mniejszej) oznacza, ĝe zostanie uĝyta wartoĂÊ domyĂlna dla danej implementacji systemu. Argument bindAddr przypisuje dane gniazdo do konkretnego adresu IP. Jest to uĝytecz- ne w sytuacji, gdy komputer (urzÈdzenie) posiada wiÚcej niĝ jeden adres IP. W takiej sytuacji podanie parametru bindAddr pozwala na akceptowanie wyïÈcznie poïÈczeñ przychodzÈcych na wybrany adres. Jeĝeli argument ten bÚdzie miaï wartoĂÊ null, gniazdo bÚdzie akceptowaïo poïÈczenia przychodzÈce na wszystkie dostÚpne adresy. Przy tworzeniu obiektów typu ServerSocket moĝe zostaÊ zgïoszony jeden z nastÚ- pujÈcych wyjÈtków: T IOException — jeĝeli wystÈpi bïÈd wejĂcia-wyjĂcia, T IllegalArgumentException — jeĝeli argument okreĂlajÈcy port bÚdzie miaï wartoĂÊ spoza dopuszczalnego zakresu (0 – 65535), T SecurityException — jeĝeli brak jest uprawnieñ do utworzenia gniazda. Najwaĝniejsze metody udostÚpniane przez klasÚ ServerSocket zostaïy zebrane w tabeli 3.4. Najbardziej przydatna w tej chwili bÚdzie metoda accept, która powoduje przejĂcie gniazda w stan nasïuchiwania, czyli oczekiwania na poïÈczenie. Jeĝeli takie poïÈczenie nadejdzie, zwraca ona nowy obiekt klasy Socket, który moĝe po- sïuĝyÊ do realizacji wïaĂciwej komunikacji serwera z klientem. Tabela 3.4. Wybrane metody klasy ServerSocket Typ rezultatu Metoda Socket accept() Opis Oczekuje na poïÈczenia i akceptuje je, tworzÈc nowe obiekty klasy Socket. void void void bind(SocketAddress endpoint) WiÈĝe gniazdo z adresem i portem okreĂlonymi przez argument endpoint. bind(SocketAddress endpoint, int backlog) WiÈĝe gniazdo z adresem i portem okreĂlonymi przez argument endpoint. Argument backlog okreĂla rozmiar kolejki wejĂciowej. close() Zamyka gniazdo. Rozdziaï 3. • Programowanie sieciowe 53 Tabela 3.4. Wybrane metody klasy ServerSocket — ciÈg dalszy Typ rezultatu Metoda Opis Zwraca lokalny adres IP, do którego przypisane jest gniazdo. Zwraca lokalny port, na którym nasïuchuje gniazdo. Zwraca informacje o adresie, do którego jest podïÈczone gniazdo, lub wartoĂÊ null, jeĝeli gniazdo nie zostaïo powiÈzane. Zwraca parametr SO_TIMEOUT dla gniazda. Zwraca true, jeĝeli gniazdo zostaïo zamkniÚte. InetAddress getInetAddress() int getLocalPort() SocketAddress getLocalSocketAddress() getSoTimeout() isClosed() int boolean int String setSoTimeout(int timeout) Ustawia parametr SO_TIMEOUT dla gniazda. toString() Zwraca tekstowy opis gniazda. Warto zwróciÊ uwagÚ na metodÚ setSoTimeout, ustawiajÈcÈ parametr SO_TIMEOUT gniazda. Parametr ten okreĂla, jak dïugo metoda accept ma czekaÊ na przychodzÈce poïÈczenie. DomyĂlnie jest to wartoĂÊ nieskoñczona, czyli oczekiwanie nie zo- stanie przerwane. Moĝemy ten stan jednak zmieniÊ, korzystajÈc z wymienionej me- tody i podajÈc czas oczekiwania w milisekundach. Wtedy, jeĝeli po wywoïaniu metody accept w podanym czasie nie nadejdzie ĝadne poïÈczenie, zostanie wyge- nerowany wyjÈtek SocketTimeoutException. Jak zatem utworzyÊ najprostszy serwer, którego jedynym zadaniem byïoby wyĂwietla- nie parametrów poïÈczenia z klientem? Zostaïo to zobrazowane w Êwiczeniu 3.5. m W I C Z E N I E 3.5 Tworzenie gniazda serwerowego Napisz program serwera, który bÚdzie oczekiwaï na wybranym porcie na poïÈcze- nie. Po nawiÈzaniu poïÈczenia naleĝy wyĂwietliÊ jego parametry i zakoñczyÊ dziaïanie aplikacji. import java.net.*; import java.io.*; public class Server { public static void main(String args[]) { ServerSocket serverSocket = null; Socket socket = null; try{ serverSocket = new ServerSocket(6666); 54 Java • mwiczenia zaawansowane } catch(IOException e){ System.out.println( Bđæd przy tworzeniu gniazda serwerowego. ); System.exit(-1); } try{ socket = serverSocket.accept(); } catch(IOException e){ System.out.println(e); } System.out.println(socket); try{ serverSocket.close(); } catch(IOException e){ System.out.println( Bđæd przy zamykaniu gniazda serwerowego ); } } } Na poczÈtku funkcji main zostaïy umieszczone dwie zmienne serverSocket (dla gniazda serwerowego) oraz socket (dla gniazda klienckiego). Obiekt typu ServerSocket tworzony jest w bloku try za pomocÈ jednoargumentowego konstruktora, któremu w postaci parametru przekazywana jest wartoĂÊ 6666. To oznacza, ĝe gniazdo, o ile uda siÚ je utworzyÊ, bÚdzie nasïuchiwaïo (oczekiwaïo na poïÈczenia) na porcie o takim wïaĂnie numerze. Blok try jest potrzebny, bowiem przy wywoïywaniu konstruktora moĝe wystÈpiÊ wyjÈtek. W takiej sytuacji jest on przechwytywany w bloku catch, na ekranie pojawia siÚ zwiÈzany z nim komunikat i serwer koñczy dziaïanie (dziÚki wywoïaniu statycznej metody exit klasy System). Po utworzeniu gniazda wywoïywana jest jego metoda accept, a rezultat jej dziaïania przypisuje siÚ zmiennej socket reprezentujÈcej gniazdo klienckie: socket = serverSocket.accept(); Od tego momentu serwer bÚdzie oczekiwaï na poïÈczenia na porcie 6666. Gdy na- dejdzie takie poïÈczenie, metoda accept zakoñczy dziaïanie i zwróci obiekt klasy Socket, który bÚdzie mógï byÊ uĝyty do transmisji danych z klientem. Powyĝsza instrukcja jest ujÚta w blok try…catch, gdyĝ podczas oczekiwania moĝe wystÈpiÊ wyjÈtek. Po uzyskaniu gniazda klienckiego jego stan jest wyĂwietlany przez przekazanie obiektu socket metodzie println (System.out.println(socket)). To spowoduje wywoïa- nie metody toString z klasy Socket i wyĂwietlenie uzyskanego ciÈgu znaków na ekranie. Na zakoñczenie gniazdo jest zamykane za pomocÈ metody close. Rozdziaï 3. • Programowanie sieciowe 55 Do sprawdzenia poprawnoĂci dziaïania aplikacji z gniazdem serwerowym potrzebny bÚdzie program klienta. BÚdzie on wykonywaï poïÈczenie z adresem i portem okreĂlo- nymi w wierszu wywoïania oraz, po nawiÈzaniu poïÈczenia, wyĂwietlaï dane doty- czÈce gniazda klienckiego. DziaïajÈcy w ten sposób kod zostaï przedstawiony w Êwi- czeniu 3.6. m W I C Z E N I E 3.6 Klient ïÈczÈcy siÚ z serwerem Napisz program klienta ïÈczÈcy siÚ z adresem i portem podanymi jako argumenty wywoïania. Program powinien wyĂwietliÊ parametry poïÈczenia. import java.net.*; import java.io.*; public class Client { public static void main(String args[]) { if (args.length 2){ System.out.println( Wywođanie programu: Client host port ); System.exit(-1); } String host = args[0]; int port = 0; try{ port = new Integer(args[1]).intValue(); } catch(NumberFormatException e){ System.out.println( Nieprawidđowy argument: port ); System.exit(-1); } Socket socket = null; try{ socket = new Socket(host, port); } catch(UnknownHostException e){ System.out.println( Nieznany host. ); } catch(IOException e){ System.out.println(e); System.exit(-1); } System.out.println(socket); } } Na poczÈtku badane jest, czy przy wywoïywaniu programu zostaïy przekazane co najmniej dwa argumenty, czyli czy liczba elementów tablicy nie jest mniejsza od 2. JeĂli jest mniejsza, wyĂwietlany jest komunikat o prawidïowym sposobie wywoïania i aplikacja koñczy dziaïanie. W przeciwnym przypadku wartoĂÊ pierwszego argu- mentu wywoïania (wartoĂÊ komórki tablicy args o indeksie 0) jest przypisywana 56 Java • mwiczenia zaawansowane zmiennej pomocniczej host. Powstaje teĝ zmienna port o poczÈtkowej wartoĂci 0. Potem nastÚpuje próba przetworzenia ciÈgu znaków z drugiego argumentu (war- toĂÊ komórki tablicy args o indeksie 1) na wartoĂÊ typu int i przypisanie jej zmien- nej port. W tym celu tworzony jest nowy obiekt typu Integer, któremu w konstruk- torze jest przekazywana wartoĂÊ args[1], i wywoïywana jest metoda intValue. Jeĝeli konwersja zakoñczy siÚ sukcesem (ciÈg zawarty w args[1] bÚdzie reprezen- towaï prawidïowÈ liczbÚ), zostanie wykonana dalsza czÚĂÊ programu. W prze- ciwnym razie zostanie zgïoszony wyjÈtek NumberFormatException, który zostanie przechwycony w bloku catch. Na ekranie pojawi siÚ wtedy odpowiedni komunikat i aplikacja zakoñczy dziaïanie. Po wykonaniu opisanych czynnoĂci nastÚpuje utworzenie gniazda klienckiego o adresie i porcie wskazywanych przez zmienne host i port. Odbywa siÚ to na takich samych zasadach jak we wczeĂniejszych Êwiczeniach. JeĂli gniazdo uda siÚ utwo- rzyÊ, wyĂwietlane sÈ jego parametry, jeĝeli zaĂ wystÈpi jeden z wyjÈtków, zosta- nie obsïuĝony przez odpowiedni blok catch. m W I C Z E N I E 3.7 Testowanie poïÈczenia miÚdzy klientem i serwerem Przetestuj dziaïanie klienta i serwera z Êwiczeñ 3.5 i 3.6. W jednej konsoli naleĝy wywoïaÊ serwer (zacznie wtedy oczekiwaÊ na poïÈcze- nie), a w drugiej — klienta. Klientowi naleĝy podaÊ odpowiednie argumenty wy- woïania: jako nazwÚ localhost lub 127.0.0.1 (lub teĝ przypisany do komputera inny adres IP), a jako port — wartoĂÊ 6666. Klient nawiÈĝe wtedy poïÈczenie z serwe- rem. Na konsoli serwera zostanÈ wyĂwietlone informacje z gniazda serwerowego, m.in. numer portu, z którego poïÈczyï siÚ klient, a na konsoli klienta — informacje z gniazda klienckiego. Moĝna teĝ ponownie wywoïaÊ klienta bez uruchomionego serwera, aby zobaczyÊ obsïugÚ wyjÈtku ConnectException powstaïego ze wzglÚdu na odrzucenie poïÈczenia (rysunek 3.4). Rysunek 3.4. Klient i serwer dziaïajÈ zgodnie z zaïoĝeniami
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Java. Ćwiczenia zaawansowane. Wydanie II
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: