Idag:
|
Klicka på startknappen i den lilla mediaspelaren ovan för att lyssna på lektionen. (Man kan behöva vänta en stund på att ljudfilen laddas ner.) Om mediaspelaren inte syns, eller om det inte fungerar av något annat skäl, kan man klicka här för att ladda ner mp3-filen (ca 37 minuter, ca 17 megabyte). Beroende på hur webbläsaren är konfigurerad kan det kräva ett separat mp3-spelarprogram av något slag.
|
|
|
|
1 import java.net.ServerSocket; 2 import java.net.Socket; 3 4 import java.io.InputStreamReader; 5 import java.io.OutputStreamWriter; 6 import java.io.BufferedReader; 7 import java.io.BufferedWriter; 8 import java.io.PrintWriter; 9 import java.io.IOException; 10 11 12 public class HelloServer { 13 public static final int PORT = 2000; 14 public static void main(String[] args) throws IOException { 15 ServerSocket s = new ServerSocket(PORT); 16 System.out.println("Servern: Lyssnar..."); 17 Socket socket = s.accept(); 18 System.out.println("Servern: Uppkoppling accepterad."); 19 20 BufferedReader from_client = new BufferedReader(new InputStreamReader(socket.getInputStream())); 21 PrintWriter to_client = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); 22 // true: PrintWriter is line buffered 23 24 while (true) { 25 String inline = from_client.readLine(); 26 System.out.println("Servern: Tog emot '" + inline + "'"); 27 // Not: inline == "quit" 28 if (inline == null || inline.equals("quit")) 29 break; 30 to_client.println("HELLO, CLIENT! YOU SAID: " + inline); 31 } 32 } // main 33 } // HelloServer |
1 import java.net.Socket; 2 import java.net.InetAddress; 3 4 import java.io.InputStreamReader; 5 import java.io.OutputStreamWriter; 6 import java.io.BufferedReader; 7 import java.io.BufferedWriter; 8 import java.io.PrintWriter; 9 import java.io.IOException; 10 11 public class HelloClient { 12 public static final int PORT = 2000; 13 public static void main(String[] args) throws IOException { 14 InetAddress addr; 15 if (args.length >= 1) 16 addr = InetAddress.getByName(args[0]); 17 else 18 addr = InetAddress.getByName(null); 19 20 Socket socket = new Socket(addr, PORT); 21 22 BufferedReader from_server = new BufferedReader(new InputStreamReader(socket.getInputStream())); 23 PrintWriter to_server = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); 24 // true: PrintWriter is line buffered 25 26 BufferedReader kbd_reader = new BufferedReader(new InputStreamReader(System.in)); 27 28 String line_from_user; 29 while (true) { 30 System.out.print("Skriv en rad: "); 31 line_from_user = kbd_reader.readLine(); 32 to_server.println(line_from_user); 33 String line_from_server = from_server.readLine(); 34 if (line_from_server == null) 35 break; 36 System.out.println("Från servern: " + line_from_server); 37 } 38 } // main 39 } // HelloClient |
1 class BoringThread extends Thread { 2 static int numberOfThreads = 0; 3 int threadNumber = ++numberOfThreads; 4 5 public void run() { 6 int nrReps = 0; 7 while (true) { 8 System.out.print("Tråd nummer " + threadNumber + " har kört "); 9 System.out.println(++nrReps + " varv i loopen."); 10 } 11 } // run 12 } // class BoringThread 13 14 public class ThreeBoringThreads { 15 public static void main(String[] args) { 16 BoringThread t1 = new BoringThread(); 17 BoringThread t2 = new BoringThread(); 18 BoringThread t3 = new BoringThread(); 19 t1.start(); 20 t2.start(); 21 t3.start(); 22 } // main 23 } // class ThreeBoringThreads |
1 class BetterThread extends Thread { 2 static int numberOfThreads = 0; 3 int threadNumber = ++numberOfThreads; 4 5 public void run() { 6 int nrReps = 0; 7 while (true) { 8 synchronized ("fnord") { 9 System.out.print("Tråd nummer " + threadNumber + " har kört "); 10 System.out.println(++nrReps + " varv i loopen."); 11 } 12 } 13 } // run 14 } // class BetterThread 15 16 public class ThreeBetterThreads { 17 public static void main(String[] args) { 18 BetterThread t1 = new BetterThread(); 19 BetterThread t2 = new BetterThread(); 20 BetterThread t3 = new BetterThread(); 21 t1.start(); 22 t2.start(); 23 t3.start(); 24 } // main 25 } // class ThreeBetterThreads |
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 4 public class ServerListenerThread extends Thread { 5 private final ChatClient owner; 6 private final BufferedReader from_server; 7 private boolean quit = false; 8 9 public ServerListenerThread(ChatClient owner, BufferedReader from_server) { 10 this.owner = owner; 11 this.from_server = from_server; 12 } 13 14 public void run() { 15 while (! quit) { 16 String line_from_server; 17 try { 18 line_from_server = from_server.readLine(); 19 if (line_from_server == null) { 20 System.out.println("Fick inga data från servern"); 21 quit = true; 22 } 23 else { 24 System.out.println(line_from_server); 25 } 26 } 27 catch (IOException e) { 28 System.out.println("Fel vid mottagning från servern"); 29 quit = true; 30 } 31 32 } // while 33 owner.please_quit(); 34 } // run 35 36 public void please_quit() { 37 quit = true; 38 } 39 } // class ServerListenerThread |
1 // ChatClient.java 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.io.OutputStreamWriter; 8 import java.io.PrintWriter; 9 import java.net.InetAddress; 10 import java.net.Socket; 11 12 public class ChatClient { 13 private static final int PORT = 2001; 14 // private static final String DEFAULT_HOST = "basen.oru.se"; 15 private static final String DEFAULT_HOST = "localhost"; 16 private boolean quit = false; 17 18 private final BufferedReader from_user; 19 private final BufferedReader from_server; 20 private final PrintWriter to_server; 21 private final String user_name; 22 private final ServerListenerThread server_listener; 23 24 public ChatClient(BufferedReader from_user, BufferedReader from_server, PrintWriter to_server, String user_name) { 25 this.from_user = from_user; 26 this.from_server = from_server; 27 this.to_server = to_server; 28 this.user_name = user_name; 29 this.server_listener = new ServerListenerThread(this, from_server); 30 server_listener.start(); 31 } // ChatClient 32 33 public void please_quit() { 34 quit = true; 35 } 36 37 private void run() { 38 System.out.println("Uppkopplad! Loggar in..."); 39 to_server.println("LOGIN " + user_name); 40 System.out.println("Nu kan du chatta! Skriv rader, med ENTER efter varje rad.\n"); 41 42 while (!quit) { 43 try { 44 String line_from_user = from_user.readLine(); 45 // System.out.println("Från tangentbordet: " + line_from_user); 46 // System.out.println("Till servern: " + line_from_user); 47 to_server.println(line_from_user); 48 if (line_from_user.equals("LOGOUT")) { 49 quit = true; 50 server_listener.please_quit(); 51 } 52 } 53 catch (IOException e) { 54 System.out.println("Kunde inte läsa en rad från användaren."); 55 e.printStackTrace(); 56 quit = true; 57 } 58 } 59 System.out.println("Nedkopplad från servern."); 60 } // run 61 62 public static void main(String[] args) throws IOException { 63 System.out.println("Välkommen till chatten!"); 64 BufferedReader kbd_reader = new BufferedReader(new InputStreamReader(System.in)); 65 String user_name; 66 do { 67 System.out.print("Skriv ditt namn: "); 68 user_name = kbd_reader.readLine(); 69 } while (user_name.equals("")); 70 71 InetAddress addr; 72 if (args.length >= 1) 73 addr = InetAddress.getByName(args[0]); 74 else 75 addr = InetAddress.getByName(DEFAULT_HOST); 76 int port; 77 if (args.length >= 2) 78 port = Integer.parseInt(args[1]); 79 else 80 port = PORT; 81 System.out.println("Kopplar upp mot servern..."); 82 83 Socket socket = new Socket(addr, port); 84 85 BufferedReader from_server = new BufferedReader(new InputStreamReader(socket.getInputStream())); 86 PrintWriter to_server = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); 87 // true: PrintWriter is line buffered 88 89 ChatClient cc = new ChatClient(kbd_reader, from_server, to_server, user_name); 90 cc.run(); // Use the default execution thread 91 } // main 92 } // class ChatClient |
Tillägg 28 september 2012:
Det är kodsnutten new Socket(addr, port) som gör själva uppkopplingen mot servern. I skrivbords-Java-exemplet ovan gör vi det i den så kallade huvudtråden. Vi skapar ingen särskild tråd för det. I Android bör man inte göra så, utan man bör skapa en särskild tråd när man ska göra någon nätverksaktivitet. Här är huvudtråden den så kallade GUI-tråden, som används för att rita upp användargränssnittet. Om den tråden är upptagen med att koppla upp sig mot en server, eller vänta på data, ser det ut som om appen har hängt sig. I nyare versioner av Android (API-nivå 11 och högre) är det som default förbjudet att göra så, och om man försöker kastas ett NetworkOnMainThreadException. Läs dokumentet Designing for Responsiveness! |
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.IOException; 4 import java.io.InputStreamReader; 5 import java.io.OutputStreamWriter; 6 import java.io.PrintWriter; 7 import java.net.ServerSocket; 8 import java.net.Socket; 9 10 public class ChatServer { 11 public static final int PORT = 2001; 12 13 public static void main(String[] args) { 14 final SimpleLogger logger = new SimpleLogger("ChatServer"); 15 final MainServerThread server = new MainServerThread(); 16 server.start(); 17 18 try { 19 ServerSocket s; 20 s = new ServerSocket(PORT); 21 logger.log("Server-socketen: " + s); 22 logger.log("Servern lyssnar..."); 23 24 while(true) { 25 logger.log("Väntar på uppkoppling från klient..."); 26 // Blocks until a connection occurs: 27 Socket socket = s.accept(); 28 logger.log("Uppkoppling från klient accepterad."); 29 logger.log("Den nya socketen: " + socket); 30 final BufferedReader from_client = new BufferedReader(new InputStreamReader(socket.getInputStream())); 31 final PrintWriter to_client = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); 32 // true: PrintWriter is line buffered 33 server.new_client(from_client, to_client); 34 } 35 } catch (IOException e) { 36 logger.log("IOException: " + e); 37 e.printStackTrace(); 38 } 39 } // main 40 } // class ChatServer |
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.PrintWriter; 4 5 public class ClientListenerThread extends Thread { 6 private final MainServerThread owner; 7 private final BufferedReader from_client; 8 final PrintWriter to_client; 9 private static int instances = 0; 10 private int number = ++instances; 11 private final SimpleLogger logger = new SimpleLogger("ConnectionWaiterThread " + number); 12 private String user_name = null; 13 private boolean quit = false; 14 15 public ClientListenerThread(MainServerThread owner, BufferedReader from_client, PrintWriter to_client) { 16 this.owner = owner; 17 this.from_client = from_client; 18 this.to_client = to_client; 19 20 } 21 22 public void run() { 23 while (! quit) { 24 String line_from_client; 25 try { 26 line_from_client = from_client.readLine(); 27 logger.log("Från klienten: " + line_from_client); 28 if (line_from_client == null || line_from_client.equals("LOGOUT")) { 29 owner.client_has_disconneted(this); 30 quit = true; 31 } 32 else if (line_from_client.equals("SHUTDOWN")) { 33 System.exit(0); 34 // quit = true; 35 } 36 else if (line_from_client.startsWith("LOGIN ")) { 37 user_name = line_from_client.substring(6); 38 } 39 else { 40 owner.received_from_client(this, line_from_client); 41 } 42 } 43 catch (IOException e) { 44 logger.log("Tappat kontakten med klienten."); 45 e.printStackTrace(); 46 quit = true; 47 } 48 } // while 49 owner.client_has_disconneted(this); 50 } // run 51 52 public String getUserName() { 53 if (user_name == null) 54 return "Namnlös chattare nummer " + number; 55 else 56 return user_name; 57 } 58 59 public void send(String line) { 60 to_client.println(line); 61 } 62 } // class ClientListenerThread |
Klienten skickar rader som ser ut så här till servern:
|
1 import java.io.BufferedReader; 2 import java.io.PrintWriter; 3 import java.util.LinkedList; 4 5 // In the chat application, this doesn't really need to be a thread 6 7 public class MainServerThread extends Thread { 8 final SimpleLogger logger = new SimpleLogger("MainServerThread"); 9 private final LinkedList<ClientListenerThread> clients = new LinkedList<ClientListenerThread>(); 10 11 public synchronized void new_client(BufferedReader from_client, PrintWriter to_client) { 12 final ClientListenerThread c = new ClientListenerThread(this, from_client, to_client); 13 c.start(); 14 clients.add(c); 15 } 16 17 public synchronized void client_has_disconneted(ClientListenerThread c) { 18 clients.remove(c); 19 } 20 21 public void received_from_client(ClientListenerThread originator, String line_from_client) { 22 String sender_name = originator.getUserName(); 23 IncomingMessage m = new IncomingMessage(line_from_client, sender_name, originator); 24 put(m); 25 } 26 27 private class IncomingMessage { 28 public final String line; 29 public final ClientListenerThread originator; 30 public IncomingMessage(String line, String sender_name, ClientListenerThread originator) { 31 this.line = line; 32 this.originator = originator; 33 } 34 } 35 36 private LinkedList<IncomingMessage> inqueue = new LinkedList<IncomingMessage>(); 37 38 public synchronized void put(IncomingMessage m) { 39 inqueue.addLast(m); 40 notify(); 41 logger.log("Efter put, kö nu " + inqueue.size()); 42 } 43 44 public synchronized IncomingMessage get() { 45 while (inqueue.isEmpty()) { 46 try { 47 wait(); 48 } catch (InterruptedException e) { 49 logger.log("wait interrupted"); 50 e.printStackTrace(); 51 } 52 } 53 IncomingMessage b = inqueue.getFirst(); 54 inqueue.removeFirst(); 55 notify(); 56 logger.log("Efter get, kö nu " + inqueue.size()); 57 return b; 58 } 59 60 private boolean quit = false; 61 62 public void run() { 63 while (! quit) { 64 IncomingMessage m = get(); // Will wait for a message 65 final String line = m.line; 66 final ClientListenerThread originator = m.originator; 67 final String sender_name = originator.getUserName(); 68 for (ClientListenerThread receiver : clients) { 69 if (receiver != originator) 70 receiver.send(sender_name + ": " + line); 71 } 72 } 73 } // run 74 } // class MainServerThread |
Tillägg 6 december 2015: Det finns ett fel i programkoden ovan. Loopen på rad 68-71, som går igenom alla klienterna i listan clients och skickar meddelandet till var och en av dem, borde inneslutas i en synchronized (this) { }. Annars kan metoderna new_client och client_has_disconneted anropas från en annan tråd och råka ändra på innehållet i listan clients samtidigt som vi går igenom listan. Då kraschar servertråden med ConcurrentModificationException, och chatservern kommer att sluta vidarebefordra meddelanden. |
1 import java.text.SimpleDateFormat; 2 import java.util.Date; 3 4 public class SimpleLogger { 5 private final String program_name; 6 private final SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z"); 7 8 public SimpleLogger(String program_name) { 9 this.program_name = program_name; 10 } 11 12 public void log(String message) { 13 Date now = new Date(); 14 String formatted_date = date_format.format(now); 15 String line = program_name + " " + formatted_date + ": " + message; 16 System.out.println(line); 17 } 18 } // class SimpleLogger |