Klient och serverprogrammering: Socketar Föreläsning 9 Fördjupning se tex Harold, Hall och/eller Tut Innehåll • Inledning • Några enkla exempel • Pekare till och kort beskrivning av större exempel Speciella referenser • Harold, dvs boken ”Java Network Programming” • Hall, "CORE Web Programming” • Budd, ”Understanding Object-Oriented Programming with Java”, 2ed år 2000 • Tut, dvs tutorial (~kurs) som finns hos SUN på nätet http://www.javasoft.com/docs/books/tutorial/networking/index.html • Fler (och större) exempel i katalogen http://www.nada.kth.se/kurser/kth/2D4334/00-01/contents/exempel.html previous next Socketar Klienter och servrar (som sagts tidigare …) • Dom flesta moderna nätverksprogram baseras på en klient-server-modell • En server är ett program som erbjuder tjänster • En klient är ett program som frågar en server om tjänster • En server väntar på att klienter skall ansluta • En klient initierar en "konversation" previous next 2 Socketar Socketar • Definition: En socket är en ändpunkt för en tvåvägskommunikation mellan två program som körs i nätverket. En socket är bunden till ett portnummer så att underliggande lager kan identifiera vart data skall skickas. • Socketar finns av två typer – Serversocketar som väntar på att klienter skall ansluta sig – Klientsocketar som ansluter till servrar • I Java representeras dessa av klasserna – ServerSocket och Socket previous next 3 Socketar Varför socketar • Ger oss möjlighet att på ett smidigt och uniformt sätt kommunicera mellan maskiner av olika typer • Möjliggör programspråksoberoende kommunikation – Enkelt att få program som är skrivna i olika programspråk att kommunicera previous next 4 Socketar Socketar typiskt klientprogram 1. Skapa en socket. 2. Öppna in- och utström mot socketen. 3. Läs från och skriv på socketen. 4. Stäng strömmarna. 5. Stäng socketen. previous next 5 Socketar ... 1. Socket socket = new Socket(HOSTNAME, PORT). 2. out = new PrintWriter(socket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader( socket.getInputStream())); 3. while ((userInput = stdIn.readLine()) != null) {out.println(userInput); System.out.println("från servern:" + in.readLine());}. 4. in.close(); out.close();. 5. socket.close(). previous next 6 Socketar Socketar typiskt serverprogram 1. Skapa en server-socket. 2. Lyssna efter anslutande klienter 3. Skapa socket mot varje anslutande klient 4. Öppna in- och utström mot klientsocketerna. 5. Läs från och skriv på klientsocketen. 6. Stäng strömmarna. 7. Stäng klientsocketerna. 8. Stäng serversocketen. previous next 7 Socketar Exempel enkel server/klient app: servern /* Deklarera en serversocket: theServer (som lyssnar efter klienter), klientsocket: theConnection (som tar hand om ansluten klient), utdataström: p (för att skicka information till klienten) */ ServerSocket theServer; Socket theConnection; PrintWriter p; //Öppna serversocket på PORTNUMMER theServer = new ServerSocket(PORTNUMMER); while (VILLKOR) {//Så länge som VILLKOR är sant fortsätter vi theConnection = theServer.accept(); //Vänta till klient ansluter p = new PrintWriter(theConnection.getOutputStream()); p.println(INFORMATION); //Skicka INFORMATION till klienten theConnection.close(); // avbryt förbindelsen med klienten } theServer.close(); //Stäng serversocketen previous next 8 Socketar ... exempel kod (server) import java.net.*; import java.io.*; import java.util.Date; public class dayTimeServer { public final static int daytimePort = 4711; public static void main(String[] args) { ServerSocket theServer; Socket theConnection; PrintWriter p; try { theServer = new ServerSocket(daytimePort); //forts nästa sida previous next 9 Socketar ... try { while (true) { theConnection = theServer.accept(); System.out.println("Connection: "+ theConnection); p = new PrintWriter( theConnection.getOutputStream()); p.println(new Date()); theConnection.close(); } //end while } catch (IOException e) { theServer.close(); System.err.println(e); } } catch (IOException e) {System.err.println(e);} } } previous next 10 Socketar Exempel enkel server/klient app: klienten /* Deklarera en socket: theSocket (som som ansluter till servern), namn på severn: hostname (dvs servermaskinens ip-adress), indataström: inputStream (för att ta emot information från servern) */ Socket theSocket; String hostname; DataInputStream inputStream; //Skapa socket theSocket = new Socket(hostname, 4711); //indataström som läser från socketen inputStream = new DataInputStream(theSocket.getInputStream()); // ta emot information från servern String theTime = inputStream.readLine(); System.out.println("It is " + theTime + " at " + hostname); theSocket.close(); previous next 11 Socketar ... exempel kod (klient) import java.net.*; import java.io.*; public class daytimeClient { public static void main(String[] args) { Socket theSocket; String hostname; DataInputStream inputStream; if (args.length > 0) { hostname = args[0]; } else { //om ingen ip-adress ges så använder vi lokala maskinens hostname = "localhost"; } previous next 12 Socketar ... try { theSocket = new Socket(hostname, 4711); inputStream = new DataInputStream(theSocket.getInputStream()); String theTime = inputStream.readLine(); System.out.println("It is " + theTime + " at " + hostname); } // end try catch (UnknownHostException e) { System.err.println(e); } finally {theSocket.close();} catch (IOException e) { System.err.println(e); } } } previous next 13 Socketar Fasta portar • Vi kan ansluta oss till fasta portar med på förhand given service på dom flesta datorer • Tex – 25 för mail – 144 för news – 23 för telnet • En annan användbar port för att testa förbindelser eller egen klient är echo-porten nr: 7 • Port 0-1023 reserverade för speciella typer av service – tex port 80 är den normala WWW-porten previous next 14 Socketar Enkelt test Ett exempel som ansluter sig till “standardservicen” echo (på port 7) som helt enkelt bara skickar tillbaks den text man skickar till den. Importera klasser för io och nät import java.io.*; import java.net.*; public class EchoClient { public static void main(String[] args) throws IOException { Socket echoSocket = null; PrintWriter out = null; BufferedReader in = null; try { echoSocket = new Socket(”faun.nada.kth.se", 7); out = new PrintWriter(echoSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));} catch (UnknownHostException e) { System.err.println("Don't know about host: faun."); System.exit(1);} catch (IOException e) { System.err.println("Couldn't get I/O for the connection to: faun."); System.exit(1); } Skapa klient kopplad mot en av NADAs datorer Samt in- och utström previous next 15 Socketar ... Ström mot terminalen BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String userInput; Så länge som användaren ger input skicka det hela till socketen, läs svaret samt eka det på terminalen while ((userInput = stdIn.readLine()) != null) { out.println(userInput); System.out.println("echo: " + in.readLine()); } out.close(); in.close(); stdIn.close(); echoSocket.close(); } } previous next 16 Socketar En klient som ansluter till en server och hämtar angiven URL Ett exempel med ett klientprogram som ansluter till angiven URL och hämtar innehållet i aktuell fil. Utmatningen sker antingen till given fil eller till terminalen. import java.io.*; import java.net.*; public class HttpClient { public static void main(String[] args) { try { Första argumentet if ((args.length != 1) && (args.length != 2)) URL:en throw new IllegalArgumentException("Wrong number of arguments"); Andra argumentet eventuell fil dit utmatningen skall ske previous OutputStream to_file; if (args.length == 2) to_file = new FileOutputStream(args[1]); else to_file = System.out; next 17 Socketar ... Dela upp URL:en på sina beståndsdelar Skapa socket mot angiven värd och port URL url = new URL(args[0]); String protocol = url.getProtocol(); if (!protocol.equals("http")) throw new IllegalArgumentException("URL must use 'http:' protocol"); String host = url.getHost(); int port = url.getPort(); if (port == -1) port = 80; // om ingen port given använd defaultporten String filename = url.getFile(); Socket socket = new Socket(host, port); Skapa in- och utmatningsströmm ar mot servern InputStream from_server = socket.getInputStream(); PrintWriter to_server = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); Skicka förfrågan till servern mha GET to_server.println("GET " + filename); to_server.flush(); // Se till att det hela skickas på en gång! previous next 18 Socketar ... Skapa buffert för att läsa det servern skickar byte[] buffer = new byte[4096]; int bytes_read; Så länge som det finns något att läsa skriv det på fil (eller terminal) while((bytes_read = from_server.read(buffer)) != -1) to_file.write(buffer, 0, bytes_read); Stäng förbindelse socket.close(); to_file.close(); } catch (Exception e) { System.err.println(e); System.err.println("Usage: java HttpClient <URL> [<filename>]"); } } } previous next 19 Socketar En enkel WEB-server som bara ekar frågor som ställs till den En enkel server som bara ekar frågor som ställs till den. Kan bla användas för att se hur en fråga från en WEB-läsare ser ut eller hur data skall skickas tillbaks från en server. import java.io.*; import java.net.*; public class HttpMirror { public static void main(String args[]) { try { int port = Integer.parseInt(args[0]); Skapa serversocket på angiven port ServerSocket ss = new ServerSocket(port); for(;;) { Vänta till klient ansluter previous Argumentet anger den port som servern skall köra på Vi kör om och om igen ända tills servern termineras (med tex CTRL-C) Socket client = ss.accept(); next 20 Socketar ... Skapa in- och utmatningsströmm ar mot klienten BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream())); Skicka över protokollinformation till klienten out.println("HTTP/1.0 200 "); // Version & statuskod out.println("Content-Type: text/plain"); // typen på data som vi skickar out.println(); // Slut på huvudet out.flush(); Läs från klienten och eka tillbaks det String line; while((line = in.readLine()) != null) { if (line.length() == 0) break; out.println(line); } } previous next 21 Socketar ... out.close(); in.close(); client.close(); } } catch (Exception e) { System.err.println(e); System.err.println("Usage: java HttpMirror <port>"); } } Kör genom att 1) starta programmet på den lokala datorn java HttpMirror 4444 2) Öppna klient mot “servern” från vanlig web-läsare http://localhost:4444 Ge eventuellt argument och se hur detta ter sig http://localhost:4444/test?arg1?arg2 previous next 22 Socketar Weizenbaums klassiska Eliza (serverdelen) import java.net.*; import java.io.*; public class Therapist { static public void main (String [ ] args) { try { Therapist world = new Therapist(); } catch (IOException e) { System.out.println("Received an IO Exception" + e); } } static final public int portNumber = 5321; previous next 23 Socketar … (serverdelen) public Therapist () throws IOException { ServerSocket server = new ServerSocket(portNumber); while (true) { Socket sock = server.accept(); // start new thread to handle session Thread session = new TherapySession // Se nästa sida (sock.getInputStream(), sock.getOutputStream()); session.start(); } } } previous next 24 Socketar Terapisten med tråd som servar viss klient... import java.io.*; import java.util.Vector; import java.util.StringTokenizer; public class TherapySession extends Thread { public TherapySession (InputStream ins, OutputStream outs) { Reader isread = new InputStreamReader(ins); in = new BufferedReader(isread); out = new OutputStreamWriter(outs); } private String name = ""; private BufferedReader in; private Writer out; previous next 25 Socketar ... (terapisten) ... private String response (String text) { // answer a question with a question if (text.endsWith("?")) return "Why do you want to know?"; // break up line Vector words = new Vector(); StringTokenizer breaker = new StringTokenizer(text.toLowerCase(), " .,?!"); while (breaker.hasMoreElements()) words.addElement(breaker.nextElement()); // look for \I feel" if ((words.size() > 1) && words.elementAt(0).equals("i") && words.elementAt(1).equals("feel")) return "Why do you feel that way?"; previous next 26 Socketar ... (terapisten) ... // look for relatives for (int i = 0; i < words.size(); i++) { String relative = (String) words.elementAt(i); if (isRelative(relative)) return "Tell me more about your " + relative; } // nothing else, generic response return "Tell me more"; } private boolean isRelative (String name) { return name.equals("mother") || name.equals("father") || name.equals("brother") || name.equals("sister") || name.equals("uncle"); } previous next 27 Socketar ... (terapisten) ... public void run () { boolean continueReading = true; try { // get name out.write("Hello. Welcome to therapy. What is your name?\n"); out.flush(); name = in.readLine(); out.write("Well " + name + " what can we do for you today?\n"); out.flush(); // now read and respond while (continueReading) { String text = in.readLine(); out.write(response(text) + "\n"); out.flush(); } } catch (IOException e) { continueReading = false; } } } previous next 28 Socketar ...Eliza (klientdelen) import java.io.*; import java.net.*; public class TherapyClient { public static void main (String [ ] args) { try { TherapyClient world = new TherapyClient(); } catch (IOException e) { System.out.println("Received an IO exception " + e); } } static final public int portNumber = 5321; private BufferedReader input, term; private Writer output; previous next 29 Socketar ... (klienten) ... public TherapyClient () throws IOException { // open standard input as bufered reader term = new BufferedReader(new InputStreamReader(System.in)); // open socket as a reader and a writer Socket sock = new Socket(InetAddress.getLocalHost(), portNumber); Reader isread = new InputStreamReader(sock.getInputStream()); input = new BufferedReader(isread); output = new OutputStreamWriter(sock.getOutputStream()); previous next 30 Socketar ... (klienten) // now read and print while (true) { // read and print something from therapist String line = input.readLine(); System.out.println(line); // get our response line = term.readLine(); if (line.equals("Quit")) break; output.write(line + "\n"); output.flush(); } } } previous next 31 Socketar Meddelande-server baserad på socketar • Det sista exemplet är lite större och beskrivs på separat WEB-sida http://www.nada.kth.se/kurser/kth/2D4334/00-01/contents/exempel.html previous next 32