Java – hálózati alkalmazások Socket, URL
Protokollok • java.net: socket, URL (Uniform Resource Locators) • Protokoll: számítógépek közötti kommunikáció szabályai • Internet →TCP/IP (Transport Control Protocol/Internet Protocol) • IETF (Internet Engineering Task Force) → standardok • Java: a TCP/IP szint feletti protokollok implementációja • HTTP (HyperText Transfer Protocol) és FTP (File Transfer Protocol) használata • Predefiniált osztályok és interfészek alkalmazása (nem szükséges az implementációs részletek és adatstruktúrák ismerete)
Kliens-szerver modell • Szerver: a hálózaton keresztül érkező kliens kérések teljesítése • Web – a kliensek által kért dokumentumok biztosítása (HTTP/HTTPS) • E-mail - SMTP (Simple Mail Transfer Protocol), IMAP4 (Internet Mail Access Protocol), POP3 (Post Office Protocol) • NFS (Network File System) • FTP (File Transfer Protocol) • DNS (Domain Name Service) • NIS (Network Information Service) • TELNET, RLOGIN, SSH (Secure Shell), XDMCP (X Display Manager Control Protocol) (belépés távoli rendszerekre) • Stb.
• Kliens: használja a szerver által biztosított szolgáltatásokat. Ehhez ismernie kell a szerver címét, a kommunikációra használt portot és protkollt
Port és socket • Port: kapu a kliensek fogadásához • Egy címen több különböző szolgáltatás is futhat, különböző portokon • A port száma: 1-65535, az IETF szerint 1-1024 foglalt (80 – HTTP, 21 – FTP, 23 – TELNET stb.)
• Socket: absztrakt kommunikációs csomópont (a fogalmat a BSD UNIX vezette be) • Alacsonyszintű interfész hálózati kommunikációhoz • Azonos vagy a hálózaton belül különböző számítógépeken futó processzek közötti kommunikáció
• Java: három socket típus, adatfolyamokat (stream) használnak az üzenetek küldéséhez/fogadásához • Socket - TCP • DatagramSocket – UDP (nem kapcsolat orientált) • MulticastSocket – a DatagramSocket változata, amely több receptorhoz küldhet adatokat
Socket és ServerSocket • Kapcsolat orientált kommunikáció, TCP • Két rész: kliens és szever – a kliens kéréseket küld, a szerver válaszol • A kliens a kéréshez létrehoz egy Socket-et, a szerver készen áll a kérések fogadására (ServerSocket), a kérés fogadásakor létrehoz egy szerver oldali Socket-et, és ezen keresztül biztosítja a kért szolgáltatást. A kliensnek ismernie kell a szerver nevét (az IP cím lekéréséhez) és a használt port-ot.
Párhuzamos/szekvenciális szerver • Általában párhuzamos (parallel/concurent) szervereket alkalmazunk: minden kliens részére egy külön végrehajtási szálat hozunk létre • A szerver által végrehajtott tipikus műveletek: • 1. A szerver kioszt egy kommunikációs port-ot (ezt ismerik a kliensek) • 2. while (vannak kliensek a port-nál) { • A kapcsolat létrehozása (Socket létrehozása) • A kliens kiszolgálása (bemeneti/kimeneti adatfolyam) • A kapcsolat felbontása (Socket felszabadítása) }
A kliens által végrehajtott műveletek: • Kommunikációs port kiválasztása • Kapcsolódás a szerverhez • Socket létrehozása, adatok küldése és fogadása (adatfolyamok)
A Socket osztály • Konstruktorok: • Socket(InetAddress address, int port) • Socket(InetAddress address, int port, InetAddress localAddr, int localPort) - (a kliens cím/port megadásával) • Socket(String host, int port) • Socket(String host, int port, InetAddress localAddr, int localPort)
• Fontosabb metódusok: • • • • • • •
void close() InetAddress getInetAddress() InputStream getInputStream() InetAddress getLocalAddress() int getLocalPort() OutputStream getOutputStream() int getPort()
A ServerSocket osztály • Konstruktorok: • ServerSocket(int port) • ServerSocket(int port, int backlog) • (a várakozási sor hosszának megadásával)
• Fontosabb metódusok: • • • •
void close() Socket accept() InetAddress getInetAddress() int getLocalPort()
Példa • A kliens elküld egy karaktersort, a szerver visszaküldi nagybetűkbe konvertálva
Server.java //Source file: c:\ClientServer\ServerPackage\Server.java package ServerPackage; public class Server { public static void main(String[] args) { int port; if( args.length <1 ) { System.out.println( "Usage Server <portnumber>"); System.exit( 1 ); } try{ port = Integer.parseInt( args[ 0 ] ); } catch( NumberFormatException e ) { port = 1024; } try{ java.net.ServerSocket ss = new java.net.ServerSocket( port ); while( true ) ( new ClientHandle( ss.accept() )).start(); } catch( java.io.IOException e ) { System.out.println( "Server error "); } } }
ClientHandle.java //Source file: c:\ClientServer\ServerPackage\ClientHandle.java package ServerPackage; import java.net.Socket; import java.net.SocketException; Import java.io.*; public class ClientHandle extends Thread { Socket client; public ClientHandle(Socket client) throws SocketException { this.client = client; } public void run() { try{ InputStream in = client.getInputStream(); OutputStream out = client.getOutputStream(); BufferedReader myin = new BufferedReader(new InputStreamReader( in)); PrintWriter myout = new PrintWriter( new OutputStreamWriter( out )); String request = myin.readLine(); System.out.println( "Request: "+request); myout.println( request.toUpperCase()); myout.flush(); myin.close(); myout.close(); client.close(); } catch( java.io.IOException e ) { System.out.println("I/O error "+e ); } } }
Client.java //Source file: c:\Rose\ClientServer\ClientPackage\Client.java package ClientPackage; public class Client { private String hostname; private int hostport; private String message; public Client(String hostname, int hostport, String message) { this.hostname = hostname; this.hostport = hostport; this.message = message; doIt(); } public void doIt() { try{ java.net.Socket s = new java.net.Socket( hostname, hostport ); java.io.BufferedReader in = new java.io.BufferedReader( new java.io.InputStreamReader(s.getInputStream())); java.io.PrintWriter out = new java.io.PrintWriter( s.getOutputStream() ); out.println( message ); out.flush(); System.out.println("Answer from the server: "+in.readLine() ); s.close(); } catch( java.io.IOException e ) { System.out.println( "I/O error "+e ); } }
Client.java public static void main(String[] args) { String hostname, message; int hostport; if( args.length < 3 ) { System.out.println("Usage Client
<message>"); System.exit( 1 ); } hostname = args[ 0 ]; message = args[ 2 ]; try{ hostport =Integer.parseInt( args[ 1 ] ); } catch( NumberFormatException e ) { hostport = 1024; } Client c = new Client( hostname, hostport, message ); } }
• Más példa: egyszerű HTTP szerver
User Datagram Protocol (UDP) • Nem kapcsolat orientált • Példa: postai szolgálat, levél küldése (boríték – datagram) • Nem biztos kapcsolat: nincs visszajelzés az érkezéskor, a továbbítási útvonal nem ismert a küldés pillanatában (így ha többet küldünk egy címzetthez, a megérkezés sorrendje is bizonytalan) • Gyors, és alkalmazható olyan esetekben, amikor nem túl nagy probléma egy-két csomag elvesztése (pl. DNS)
A DatagramPacket osztály • Konstruktorok: • DatagramPacket(byte[] buf, • DatagramPacket(byte[] buf, port) • DatagramPacket(byte[] buf, • DatagramPacket(byte[] buf, address, int port)
int length) int length, InetAddress address, int int offset, int length) int offset, int length, InetAddress
• Fontosabb metódusok: • • • • • • • • • •
InetAddress getAddress() byte[] getData() int getLength() int getOffset() int getPort() void setAddress(InetAddress iaddr) void setData(byte[] buf) void setData(byte[] buf, int offset, int length) void setLength(int length) void setPort(int iport)
A DatagramSocket osztály • Konstruktorok: • DatagramSocket() (egy szabad port-ot rendel hozzá) • DatagramSocket(int port) • DatagramSocket(int port, InetAddress laddr)
• Fontosabb metódusok: • • • • • • • • •
void close() void connect(InetAddress address, int port) void disconnect() InetAddrress getInetAddress() InetAddress getLocalAddress() int getLocalPort() int getPort() void receive(DatagramPacket p) void send(DatagramPacket p)
Példa • Egy applet értesíti a szervert minden elindításakor (felhasználható pl. weboldal látogatottságának mérésére)
MessageApplet.java //Source file: c:\ClientPackage\MessageApplet.java package ClientPackage; public class MessageApplet extends java.applet.Applet { private String myHost; private int myPort; public void init() { myHost = getCodeBase().getHost(); myPort = Integer.parseInt( getParameter("PORT")); } public void sendMessage(String message) { try{ byte data[] =message.getBytes(); java.net.InetAddress addr = java.net.InetAddress.getByName( myHost ); java.net.DatagramPacket packet = new java.net.DatagramPacket( data, data.length, addr, myPort ); java.net.DatagramSocket ds = new java.net.DatagramSocket(); ds.send( packet ); ds.close(); } catch( java.io.IOException e ){ System.out.println(e ); } } public void start() { sendMessage("Pagina incarcata"); } }
A HTML fájl és a AppletServer.java • A HTML fájl tartalma:
• Az AppletServer: //Source file: c:\ServerPackage\AppletServer.java package ServerPackage; public class AppletServer { public static void main(String[] args) { try { java.net.DatagramSocket s=new java.net.DatagramSocket(Integer.parseInt(args[0])); while( true ){ //a szerver felkészül egy csomag fogadására byte data[] = new byte[1024]; java.net.DatagramPacket packet = new java.net.DatagramPacket( data,1024); //a szerver várja a csomagot s.receive( packet ); //kiveszi a csomagból az adatokat és kiírja a standard kimenetre String message = new String( packet.getData()); System.out.println("Hostname: "+ packet.getAddress().getHostName()+" "+message); } } catch( java.io.IOException e ){} } }
Uniform Resource Locator (URL) • Egy objektum Interneten keresztüli beazonosítása • Három részből áll: • protocol://hostname/objektum_neve • protocol://hostname:port/objektum_neve • • • •
vagy
Protocol: http, ftp, stb. Hostname: az objektumot tároló számítógép neve (vagy IP címe) Port: csak akkor kell megadni, ha nem standard objektum:_neve: az objetum neve és elérési útja
• URL konstruktorok Java-ban: • URL(String spec) • URL(String protocol, String host, int port, String file) • URL(String protocol, String host, String file)
• MalformedURLException –t adnak, ha valami hiányzik a specifikációból (az objektum létezése nem ellenőrzött a példányosításkor, a kivétel akkor lép fel, ha hibás paraméterátadás történt).
URL alkalmazása •
URL példányosítása: try{ URL url = new URL("http","www.cid.com.ro",3128, "index.html"); System.out.println( url.toString()); } catch( MalformedException e ){ //a kivétel kezelése }
•
Alkalmazás applettek esetében try{ URL url = new URL("http", getDocumentBase(), "index.html"); System.out.println( url.toString()); } catch( MalformedException e ){ //a kivétel kezelése }
•
Az adatok lekérése: az URL-nek megfelelő adatfolyam lekérése (openStream()) try{ URL url = new URL("http://www.cid.com.ro/index.html"); BufferedReader bin = new BufferedReader( new InputStreamReader(url.openStream())); String line; while( ( line = bin.readLine()) != null ) System.out.println( line ); } catch (Exception e ){}