Laboration D, Nätverkskommunikation



Relevanta dokument
Transport Layer. Transport Layer. F9 Meddelandesändning med UDP EDA095 Nätverksprogrammering. Java och UDP TCP/UDP

Distribuerade system. CORBA eller RMI

10 Kommunikation i Java

Tentamen Nätverksprogrammering Lösningsförslag

Objektorienterad Programkonstruktion. Föreläsning 11 6 dec 2016

Tung bakgrundsaktivitet t.ex. Aktiva objekt t.ex. Animering, simulering. DD2385 Programutvecklingsteknik Några bilder till föreläsning 9 6/5 2013

Klasser och objekt i C#

Du ska nu skapa ett litet program som skriver ut Hello World.

Tentamen Nätverksprogrammering Lösningsförslag

DI-institutionen Sid 1 av 6 Hans-Edy Mårtensson Sten Sundin

Javas Exceptions. DD2385 Programutvecklingsteknik Fler bilder till föreläsning 7 23/ Kort om Javas Exceptions Trådar i Java

Hjälp för digital röst. Mikro Værkstedet A/S

Gissa det hemliga talet

F8 Meddelandesändning med UDP

Att bekanta dig med NetBeans programmeringsmiljö och skriva några enkla program med programmeringsspråket Java.

Objektorienterad programmering D2

Tentamen i Programmering grundkurs och Programmering C

Efter att du har installerat ExyPlus Office med tillhörande kartpaket börjar du med att göra följande inställningar:

Programmera en NXT Robot

DOP-matematik Copyright Tord Persson. Bråktal Läs av vilka tal på tallinjen, som pilarna pekar på. Uppgift nr

Föreläsnings 10 - Överlagring, Konstruerare, Arv, Mer Exceptions, Reguljära Uttryck

Laboration 10 - NetBeans

Föreläsning 11 Aktiva objekt och trådar, strömmar, kommunikation DAT043,

Modul 6: Integraler och tillämpningar

4-3 Vinklar Namn: Inledning. Vad är en vinkel?

PROGRAMMERING A VB6 UTVECKLINGSVERKTYGET VISUAL BASIC

Administration Excelimport

Åtkomst och användarhandledning

Hur du arbetar med VFU-portfölj i Mondo. en lathund för student

Kungliga Tekniska Högskolan Ämneskod 2D4134 Nada Tentamensdag maj - 19 Tentamen i Objektorientering och Java Skrivtid 5 h

Instruktioner för beställning och kontoadministration för abonnenter av inlästa läromedel

Objektorienterad Programkonstruktion, DD1346 FACIT. Tentamen , kl

Idag: Dataabstraktion

Webb-bidrag. Sök bidrag på webben Gäller från

Tentamen OOP

Tentamensskrivning Nätverksprogrammering (EDA095 - FED) , kl 8-13

Tentamen Nätverksprogrammering Lösningsförslag

Snabbslumpade uppgifter från flera moment.

Föreningen Nordens lokala hemsidor

Dash and Dot. Svårighetsgraden bestämmer du själv genom att välja någon av av de 5 appar som är kopplade till Dash & Dot.

Utveckla arbetsmiljö och verksamhet genom samverkan

4 p o r t s 1 0 / m b p s

Idag. Exempel, version 2. Exempel, version 3. Ett lite större exempel

Introduktion. Den objektorienterade modellen Grundläggande begrepp Klass Klassen som abstraktion

Tentamen Nätverksprogrammering Lösningsförslag

Datakommunikation och Internet

Datorövning 2 Statistik med Excel (Office 2007, svenska)

Objektorienterad programmering i Java

Partnerskapsförord. giftorättsgods görs till enskild egendom 1, 2. Parter 3. Partnerskapsförordets innehåll: 4

ANVÄND NAVIGATIONEN I CAPITEX SÄLJSTÖD

ELEV- HANDLEDNING (Ansökan via webben)

Administrera utskick på utbildningstillfälle

Lathund, procent med bråk, åk 8

Tentamen Nätverksprogrammering Lösningsförslag

myabilia En introduktion

Välkommen till ikanobank.se

Instruktioner - Mybring Innehåll

Praktisk programmering

Tentamen Nätverksprogrammering Lösningsförslag

Mera om generik. Innehåll. Generik och arv Wildcards Vektorer och generik Generiska metoder. EDA690 (Mera om generik) HT / 24

FRÅN A TILL Ö LäraMera Ab / och Allemansdata Ab / FRÅN A TILL Ö

Lathund för överföring av rapporter och ljudfiler

Handledning för digitala verktyg Talsyntes och rättstavningsprogram. Vital, StavaRex och SpellRight

Ha det kul med att förmedla och utveckla ett knepigt område!

Vi skall skriva uppsats

Design by. Manual Jossan.exe. Manual. till programmet. Jossan.exe. E-post:

Att koda en magnetremsa i plastkortskrivare med inbyggd magnetkodare.

Föreläsning 5: Rekursion

OOP Objekt-orienterad programmering

DI-institutionen Sid 1 av 5 Hans-Edy Mårtensson Sten Sundin Micael Karlsson

Säkerhet. De onda. Vilka är farorna?

Programexempel: tärningsspel

MANUAL TILL AVTALSMALL FÖR KIST- OCH URNTRANSPORTER

Individuellt Mjukvaruutvecklingsprojekt

Här kan du läsa om vilka funktioner som finns tillgängliga i Switch King samt vilka möjligheter som finns för att sätta upp systemet (skalbarhet).

Handbok Ämnesprov 2016 Lärarinmatning I Dexter Åk 3. Uppdaterad: /HL Version: IST AB

Programvaruuppdateringar Användarhandbok

Dina inloggningsuppgifter är samma som du använder för att logga in på skolans datorer.

Hur skapar man formula r

ANVÄNDARHANDLEDNING FÖR

Tack för att du köpt vår digitala MP3-spelare. Innan du använder spelaren, läs igenom den här användarhandboken så att du vet hur spelaren fungerar.

Manual för BPSD registret. Version 6 /

Boken om Teknik. Boken om Teknik är en grundbok i Teknik för åk 4 6.

Fördjupad Java. Undantagshantering. Fel

Visma Proceedo. Beställa IT-produkter - beställare. Version 2.0 /

Kundservicerapport Luleå kommun 2015

Uppdrag: Huset. Fundera på: Vilka delar i ditt hus samverkar för att elen ska fungera?

Distribuerade Informationssystem VT-04

Träning i bevisföring

Klasser som datastrukturer

Tentamen för kursen Objektorienterad programvaruutveckling GU (DIT010)

Introduktion till arv

Uppdragsbeskrivning. Digital Skyltning. Version 1.0 Mats Persson. Distributionslista. Namn Åtgärd Info.

Frågor i ansökan om statsbidrag för läxhjälp år 2016 skolhuvudmän

Skriva B gammalt nationellt prov

Tillämpad UNIX. Laborations-PM Christian von Schultz, Programpaket och processhantering

NATIONELLA MATEMATIKTÄVLING

trafiksimulering Intro OU5 trafiksimulering

Kom-igång VictorReader Stratus 4 H som taltidningsspelare Ver

Transkript:

Laboration D, Nätverkskommunikation Avsikten med laborationen är att du ska få stifta bekantskap med kommunikation mellan datorer via internet. Java erbjuder ett flertal tekniker för kommunikation via nätverk, bl.a. Klassen URL med vars hjälp man kan hämta den fil som URLen refererar till. Olika datorer kan kommunicera med hjälp av datagram (UDP/IP). Datorerna är inte uppkopplade mot varandra. Kommunikationen sker genom paket vilka innehåller adress och portnummer hos mottagaren. Olika datorer kan kommunicera med hjälp av uppkopplad förbindelse (TCP/IP). Kommunikationen sker genom strömmar, en i vardera riktningen. Uppgift 1 UDP, Exempel 1 Man kan kommunicera med Datagram över nätverk. Men denna kommunikation garanterar ej att innehållet är oförändrat när det kommer fram. datagrammet når mottagaren. datagram kommer fram i samma ordning som de sänts. En dator skickar ett paket, vilket innehåller avsändaradress, mottagaradress och någon form av data. Datorn med mottagaradressen tar emot paketet. Kommunikationen sker över bestämda portnummer. Portnummer får vara 1025-65535. Både avsändare och mottagare av ett paket behöver ett objekt av typen DatagramSocket och ett objekt av typen DatagramPacket. Med send-metoden skickar avsändaren paketet och med receive-metoden tar mottagaren emot paketet. För att hantera adresser på internet används klassen InetAddress. Med klassmetoden public static InetAddress getbyname( String ip ) skapar man ett InetAddress-objekt. Den data ett DatagramPacket innehåller är på formen byte-array. En byte kan hålla ett värde i intervallet -128 127. Enklast är att göra en byte-array från en sträng. Det gör man genom att anropa metoden getbytes(): String str = "Hej"; byte[] data = str.getbytes(); Nu kommer arrayen data vara av storleken 3 och innehålla värdena: 72, 101, 106 Detta är heltalskod för tecken 'H', 'e' och 'j' Uppgift 1 innehåller två metoder: 1. UDPSenderA.send( String ip, int port, String[] messages) vilken skickar strängarna i messages till en vis ip-adress och port på nätet. En sträng i taget skickas och strängarna skickas med 3 sekunders mellanrum. 2. UDPReceiverA.receive( int port ) vilken lyssnar efter strängar och skriver ut de som kommer i output-fönstret. Lyssnandet sker på den port som anges vid anropet. DA129A Programmering 1 1

1. UDPSenderA.send( String ip, int port, String[] messages ) Metoden ska skicka meddelanden över ett nätverk till en bestämd mottagare-dator. Argument (parameterlistan) till metoden är ( String ip, int port, String[] messages): adressen, ip (dvs ip-nummer), till datorn som meddelandena ska skickas till. Ip-numret är en sträng. den port som mottagande datorn lyssnar på. Porten är ett heltal (int). messages, de meddelanden som ska skickas. Dessa lagras i en String-array. För att skicka ett meddelande krävs: 1. En DatagramSocket: DatagramSocket socket = new DatagramSocket(); 2. En InetAddress: InetAddress receiver = InetAddress.getByName( ip ); 3. Ett paket som innehåller InetAdress, port och meddelande: byte[] data = messages[ i ].getbytes(); // En sträng görs om till bytes DatagramPacket packet = new DatagramPacket( data, data.length, receiver, port ); 4. Ett anrop till send-metoden: socket.send( packet ); Punkterna 1, 2 och 4 ovan kan kasta IOException (eller subklasser till IOException). Därför måste de vara i en try-sats. Om vi skapar klassen UDPSenderA och skriver in ovanstående får vi följande: public class UDPSenderA { public static void send( String ip, int port, String[] messages ) { InetAddress receiver = InetAddress.getByName( ip ); DatagramSocket socket = new DatagramSocket(); DatagramPacket packet; byte[] data; for( int i = 0; i < messages.length; i++ ) { // Skicka sträng för sträng data = messages[ i ].getbytes(); packet = new DatagramPacket( data, data.length, receiver, port ); socket.send( packet ); catch( IOException e1 ) { System.out.println( e1 ); Nu skickas strängarna i snabb takt efter varandra. För att de ska skickas med tre sekunders mellanrum måste programmet pausa efter varje anrop till send-metoden. En 3 sekunder lång paus gör man genom att anropa metoden Thread.sleep med argumentet 3000: Thread.sleep( 3000 ); Metoden kan kasta ett InterruptedException vilket måste fångas. Därför lägger vi till en catch där även InteruptedException hanteras: catch( InterruptedException e2 ) { System.out.println( e2 ); Med dessa rader tillagda blir slutresultatet så här: 2

public class UDPSenderA { public static void send( String ip, int port, String[] messages ) { InetAddress receiver = InetAddress.getByName( ip ); DatagramSocket socket = new DatagramSocket(); DatagramPacket packet; byte[] data; for( int i = 0; i < messages.length; i++ ) { // Skicka sträng för sträng data = messages[ i ].getbytes(); packet = new DatagramPacket( data, data.length, receiver, port ); socket.send( packet ); Thread.sleep( 3000 ); catch( IOException e1 ) { System.out.println( e1 ); catch( InterruptedException e2 ) { System.out.println( e2 ); 2. UDPReceiverA.receive( int port ) Metoden ska lyssna efter meddelanden på en angiven port. För att ta emot ett meddelande krävs: 1. En DatagramSocket: DatagramSocket socket = new DatagramSocket( port ); 2. Ett paket för att ta emot meddelandet: byte[] data = new byte[ 256 ]; // max 256 bytes i meddelandet DatagramPacket packet = new DatagramPacket( data, data.length ); 3. Ett anrop till receive-metoden: socket.receive( packet ); // Här väntar programmet tills paket kommer 4. Göra om innehållet i paketet till ett String-objekt. För detta ändamål finns det en passande konstruktor i klassen String. String message = new String( packet.getdata(), 0, packet.getlength() ); Även i den här metoden sätter vi en try-sats runt koden. public class UDPReceiverA { public static void receive( int port ) { DatagramSocket socket = new DatagramSocket( port ); DatagramPacket packet; String message; byte[] data = new byte[ 256 ]; while( true ) { packet = new DatagramPacket( data, data.length ); socket.receive( packet ); message = new String( packet.getdata(), 0, packet.getlength() ); System.out.println( message ); // Skriver ut meddelandet catch(ioexception e) { Nu återstår det att testa send- respektive receive-metoden. 3

Test av UDPSenderA.send respektive UDPReceiverA.receive 1. Test på den egna datorn Skriv följande main-metod i klassen UDPReceiverA: UDPReceiverA.receive( 4444 ); receive-metoden kommer att lyssna på port nr 4444. Skriv följande main-metod i klassen UDPServerA: String[] meddelanden = { "Veni, vidi, vici", "Jag kom, jag såg, jag segrade", "Alea iacta est", "Tärningen är kastad", "Et tu Brute", "Även du, min käre Brutus" ; Thread.sleep( 5000 ); // vänta 5 sek med att starta sändningen catch ( InterruptedException e ) { UDPSenderA.send( "127.0.0.1", 4444, meddelanden ); Ip-adressem 127.0.0.1 är reserverad som adress till den egna datorn. Starta först main-metoden i UDPSenderA och sedan main-metoden i UDPReceiverA. Efter några sekunder så börjar meddelanden skrivas i Output-fönstret till UDPReceiverA. När samtliga meddelanden är överförda så avslutas main-tråden i UDPServerA. Men main-tråden i UDPReceiverA avslutas inte. Du får handgripligen avbryta programmet genom att välja Build Stop Build/Run. 2. Test mellan två datorer Ta reda på mottagnde dators ip-nummer genom att köra IP.java. I nedanstående exempel tänker vi oss att mottagande dator har ip: 195.178.226.29 Ändra ip-numret i anropet till send-metoden till mottagande datorns ip-nummer: UDPSenderA.send( "195.178.226.29", 4444, meddelanden ); Starta UDPReceiverA på den ena datorn och UDPSenderA på den andra datorn. UDPReceiverA måste avslutas på samma sätt som i föregående exempel. 4

Uppgift 2 UDP, Exempel 2 Vid anropet till UDPReceiver.receive-metoden så är det main-tråden som används för att vänta på att meddelanden kommer. Det innebär att programmet blir upptaget med att lyssna, och detta är som regel inte önskvärt. I stället ska man låta en separat tråd ta hand om lyssnandet. För att lösa problemet låter vi klassen UDPReceiver implementera Runnable och skriver en run-metod med samma innehåll som receive-metoden. Vi måste dessutom tala om vilken port som ska lyssnas på. Detta gör vi i konstruktorn och lagrar portens nrummer i en instansvariabel. import javax.swing.*; public class UDPReceiverB implements Runnable { private int port; public UDPReceiverB( int port ) { this.port = port; public void run() { DatagramSocket socket = new DatagramSocket( port ); DatagramPacket packet; String message; byte[] data = new byte[256]; while( true ) { packet = new DatagramPacket(data,data.length); socket.receive(packet); message = new String(packet.getData(),0,packet.getLength()); System.out.println( message ); catch(ioexception e) { Nu är det dags att skriva en ny version av receive-metoden. Den ska: 1. Skapa ett objekt av typen UDPReceiverB. UDPReceiverB receiver = new UDPReceiverB( port ); 2. Skapa en tråd med objektet som argument Thread thread = new Thread( receiver ); 3. Starta tråden (varvid run-metoden exekveras) thread.start(); Vi skriver den nya versionen av receive-metoden i klassen UDPReceiverB (metoden kan placeras i vilken klass som helst). public static void receive( int port ) { UDPReceiverB receiver = new UDPReceiverB( port ); Thread thread = new Thread( receiver ); thread.start(); Vi lägger också till en main-metod liknanden den i Uppgift1: 5

UDPReceiverB.receive( 4444 ); Så här ser den färdiga klassen ut: import javax.swing.*; public class UDPReceiverB implements Runnable { private int port; public UDPReceiverB( int port ) { this.port = port; public void run() { DatagramSocket socket = new DatagramSocket( port ); DatagramPacket packet; String message; byte[] data = new byte[256]; while( true ) { packet = new DatagramPacket(data,data.length); socket.receive(packet); message = new String(packet.getData(),0,packet.getLength()); System.out.println( message ); catch(ioexception e) { public static void receive( int port ) { UDPReceiverB receiver = new UDPReceiverB( port ); Thread thread = new Thread( receiver ); thread.start(); UDPReceiverB.receive( 4444 ); Nu kan du starta UDPSenderA och UDPReceiverB på samma sätt som i föregående Uppgift. 6

Uppgift 3 TCP, Exempel 1 Om man har behov av ökad säkerhet i kommunikationen mellan datorer kan man använda klasserna ServerSocket och Socket. ServerSocket-objektet är till för att låta andra datorer koppla upp sig till servern och Socket-objektet är till för att kommunicera med den andra datorn. I denna form av kommunikation är alltid en av datorerna server medan övriga datorer utgör klienter. Servern har ett ServerSocket-objekt och desutom ett Socket-objekt för varje klient. Varje klient har ett Socket-objekt. Kommunikationen sker genom en ström i vardera riktningen, dvs. genom ett InputStreamobjekt och ett OutputStream-objekt. Genom input-strömmen får man information från den andra datorn och genom output-strömmen överför man information till den andra datorn. Om man ska överföra enkla datatyper + strängar så kan man koppla strömmarna till objekt av typen DataInputStream respektive DataOutputStream. Om man ska överföra objekt så kan man koppla strömmarna till objekt av typen ObjectInputStream respektive ObjectOutputStream. Då det även går att överföra enkla datatyper och strängar med dessa strömmar så använder vi dem i Uppgift 3 och Uppgift 4. Uppgift 3 innehåller två metoder: 1. TCPServerC.send( int port, String[] messages) vilken låter en klient ansluta på viss port. Till den anslutna klienten överförs strängarna i messages. En sträng i taget skickas och strängarna skickas med 3 sekunders mellanrum. 2. TCPClientA.receive(String serverip, int serverport ) vilken kopplar upp mot en server och därefter tar emot strängar vilka skrivs ut i outputfönstret. 1. TCPServerC.send( int port, String[] messages ) Metoden ska skicka meddelanden över ett nätverk till den dator som kopplar upp sig. Argument (parameterlistan) till metoden är ( int port, String[] messages): den port som klienten kopplar upp sig mot. Porten är ett heltal (int). messages, de meddelanden som ska skickas. Dessa lagras i en String-array. För att en klient ska kunna koppla upp sig mot en server krävs: 1. En ServerSocket: ServerSocket serversocket = new ServerSocket( port ); 2. Ett anrop till accept-metoden: Socket socket = serversocket.accept(); // Här väntar tråden När en klient ansluter sig så skapas ett Socket-objekt. Från detta Socket-objekt får man strömmarna som man använder vid kommunikation med den andra datorn. För att servern ska kunna överföra informationen krävs 3. En output-ström av typen ObjectOutputStream (det går även bra med en DataOutputStream i det här exemplet): ObjektOutputStream output = new ObjectOutputStream( socket.getoutputstream() ); Om servern skulle ta emot information från klienten skulle även en input-ström behövas: ObjectInputStream input = new ObjectInputStream( socket.getinputstream() ); 7

4. Ett anrop till metoden writeutf följt av anrop till flush: output.writeutf( messages[ i ] ); output.flush(); Punkterna 1-4 ovan kan kasta IOException (eller subklasser till IOException). Därför sätter vi en try-sats runt dem. Eftersom vi också pausar tråden 3 sekunder så måste vi fånga InterruptedException. Genom att fånga Exception hanteras båda undantagen. Om vi skapar klassen TCPServerC och skriver in ovanstående + en paus får vi följande: import javax.swing.*; public class TCPServerC { public static void send( int port, String[] messages ) { ServerSocket serversocket = null; Socket socket = null; ObjectOutputStream output; serversocket = new ServerSocket( port ); socket = serversocket.accept(); output = new ObjectOutputStream( socket.getoutputstream() ); for( int i = 0; i < messages.length; i++ ) { output.writeutf( messages[ i ] ); output.flush(); Thread.sleep( 3000 ); // paus 3 sekunder catch( Exception e1 ) { // IOException eller InterruptedException System.out.println( e1 ); socket.close(); serversocket.close(); catch( Exception e ) { String[] meddelanden = { "Veni, vidi, vici", "Jag kom, jag såg, jag segrade", "Alea iacta est", "Tärningen är kastad", "Et tu Brute", "Även du, min käre Brutus" ; TCPServerC.send( 5555, meddelanden ); 2. TCPClientC.receive( String serverip, int serverport ) Metoden ska koppla upp sig mot en server med angiven ip och på angiven port. Sedan ska klienten ta emot strängar från servern. Dessa skrivs ut i output-fönstret. För att koppla upp sig mot datorn krävs att ett Socket-objekt konstrueras. Det finns en speciell konstruktor för ändamålet: InetAddress address = InetAddress.getByName( serverip ); Socket socket = new Socket( address, serverport ); Som argument till konstruktorn ger man ett InetAdress-objekt och porten på vilken servern lyssnar efter en klient som vill ansluta sig. Sedan skapar man strömmar för kommunikation. I detta exempel behövs endast input-ström eftersom klienten enbart ska ta emot data från servern. ObjectInputStream input = new ObjectInputStream( socket.getinputstream() ); Om klienten ska föra över information till servern krävs även en output-ström: ObjectOutputStream output = new ObjectOutputStream( socket.getoutputstream() ); 8

Nu är klienten bered att ta emot strängar genom anrop till readutf-metoden. message = input.readutf(); På samma sätt som tidigare kan vissa metoder kasta IOException. Därför är det en try-sats runt all kod. Sammantaget ser TCPClientC ut så här: import javax.swing.*; public class TCPClientC { public static void receive( String serverip, int serverport ) { Socket socket = null; InetAddress adress = InetAddress.getByName( serverip ); socket = new Socket( adress, serverport ); // koppla upp ObjectInputStream input = new ObjectInputStream( socket.getinputstream() ); String message; while( true ) { message = input.readutf(); // här väntar tråden System.out.println( message ); catch(ioexception e) { socket.close(); // avsluta Socket-objektet catch( Exception e ) { TCPClientC.receive( "127.0.0.1", 5555 ); Nu kan du testa programmen på den egna datorn. Du ska alltid starta servern först. Och därefter klienten. När en uppkopplad förbindelse bryts genereras ett IOException. Servern bryter förbindelsen genom att stänga Socket-objektet. Då genereras IOException i klienten varvid inläsnings-loopen avbryts. För att testa programmet mellan två datorer ska du ersätta det första argumentet i anropet till receive med severns ip-nummer. Starta server-programmet först och därefter klientprogrammet. Uppgift 4 TCP, Exempel 2 (Extra) Det är vissa brister i Uppgift 3: 1. I servern används main-tråden för att lyssna efter klient som vill koppla upp. Detta är som regel inte önskvärt utan en separat tråd ska sköta detta. 2. I servern hanteras kommunikationen med klienten med main-tråden. Inte heller detta är önskvärt utan en separat tråd ska sköta denna kommunikation. 3. I klienten hanteras kommunikationen med servern med main-tråden. Detta är som regel inte önskvärt utan en separat tråd ska sköta detta. 9

Servern - TCPServerD I denna lösning används inre klasser. För att bekvämt arbeta med inre klasser så startas servern genom att ett objekt av typen TCPServerD skapas. Argument till konsruktorn är port som klienter ska kunna ansluta på och array med strängar vilka ska överföras till klienten som kopplat upp sig. I servern ska det vara en tråd som lyssnar efter klienter som vill ansluta sig. En inre klass som implementerar Runnable är lämplig. Den ges namnet Connect. I run-metoden ska koden som har med uppkoppling mot servern ligga. Dessutom är accept-metoden placerad i en whileloop för att erbjuda upprepade/flera uppkopplingar. public class TCPServerD { private int port; private String[] messages; public TCPServerD( int port, String[] messages ) { this.port = port; this.messages = messages; Thread connectthread = new Thread( new Connect() ); connectthread.start(); // starta tråd som lyssnar på klienter som vill ansluta sig private class Connect implements Runnable { public void run() { ServerSocket serversocket = null; Socket socket; Thread clientthread; serversocket = new ServerSocket( port ); while( true ) { socket = serversocket.accept(); // Här ska kommunikationen med klienten startas catch( IOException e1 ) { System.out.println( e1 ); serversocket.close(); catch( Exception e ) { String[] meddelanden = { "Veni, vidi, vici", "Jag kom, jag såg, jag segrade", "Alea iacta est", "Tärningen är kastad", "Et tu Brute", "Även du, min käre Brutus" ; new TCPServerD( 5555, meddelanden ); I ovanstående kod är även main-metoden, vilken ska starta servern, medtagen. 10

I servern ska det också vara en tråd som sköter kommunikationen med klienten. Även i detta fallet är en inre klass som implementerar Runnable lämplig, Den får namnet TalkToClient. All kod fr.o.m. att output-strömmen skapas (se TCPServerC) ska vara i run-metoden. public class TCPServerD { // koden ovan private class TalkToClient implements Runnable { private Socket socket; public TalkToClient( Socket socket ) { this.socket = socket; public void run() { ObjectOutputStream oos = new ObjectOutputStream( socket.getoutputstream() ); for( int i = 0; i < messages.length; i++ ) { oos.writeutf( messages[ i ] ); oos.flush(); Thread.sleep( 3000 ); catch(exception e1 ) { System.out.println( e1 ); socket.close(); catch( IOException e ) { Det måste vara en tråd som exekverar run-metoden i klassen TalkToClient. Denna tråd skapas och startas direkt efter det att en klient kopplat upp sig (i klassen Connect): socket = serversocket.accept(); clientthread = new Thread( new TalkToClient( socket ) ); clientthread.start(); Ovanstående rader innebär att så fort en klient kopplar upp sig så startas en separat tråd för att sköta kommunikationen mot klienten. Sedan anropas accept-metoden på nytt varvid en ny klient kan ansluta sig. På detta sättet kan denna server hantera många klienter samtidgt. Klienten - TCPClientD Det är dags att skriva klienten så att kommunikationen med servern sköts av en speciell tråd. Det är ganska små ändringaar som ska göras. Klienten startas genom att ett objekt av klassen TCPClientD skapas. Argument till konstruktorn är serverns ip-adress och den port där servern ligger och lyssnar efter klienter som önskar ansluta sig. I konstruktorn skapas en tråd. Tråden startas varvid run-metoden i den inre klassen ConnectAndListenToServer exekveras. run-metoden innehåller all kod för kommunikation med servern. 11

public class TCPClientD { private String serverip; private int serverport; public TCPClientD( String serverip, int serverport ) { this.serverip = serverip; this.serverport = serverport; Thread thread = new Thread( new ConnectAndListenToServer() ); thread.start(); private class ConnectAndListenToServer implements Runnable { public void run() { Socket socket = new Socket( InetAddress.getByName(serverIP), serverport ); ObjectInputStream input = new ObjectInputStream( socket.getinputstream() ); String message; while( true ) { message = input.readutf(); System.out.println( message ); catch(ioexception e) { new TCPClientD( "127.0.0.1", 5555 ); Nu är det dags att testköra klasserna i Uppgift 4. main-metoden i TCPClientD är skriven för test på den egna datorn. Starta servern först och sedan en eller flera klienter. Varje klient får ett eget output-fönster i vilket strängarna skrivs. På det sättet ser du att servern hanterar flera klienter. När servern är färdig med en klient stängs Socket-objektet som hållt uppkopplingen mot klienten. Därigenom kastas ett IOException i klienten och klientens tråd avslutas. Eftersom accept-metoden i servern är i en oändlig loop kommer inte servern att avslutas av sig själv. Du får handgripligen avsluta servern med Build Stop Build/Run. För att testa kommunikation mellan olika datorer så ska du ta reda på ip-adressen på den maskin där servern ska köras. Sedan ändrar du i TCPClientD main så att serverns ip skickas med vid konstruktion. Sedan kan du exekvera TCPServerD på server-datorn och TCPClientD på några andra datorer. 12