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