Till KTH:s startsida Till KTH:s startsida

Labb4

Nätverk

Den här labben ska du programmera några korta program som anropar varandra via systemanrop eller över nätverk. Koden är för det mesta given och kan kopieras från labblydelsen, det som inte är givet är utkommenterat // .... Namnen på programmen måste du själv bestämma, ersätt de versalskrivna namnen i labben. Du ska även själv ansvara för kommentarer till din funktioner.

En räkneserver

Skriv en server i java som svarar på inkommande anrop. Server kan skrivas väldigt kort, endast en main-metod med en evighetsloop som för varje anrop startar en tråd som tar han om anropet. 

while (true) {
    DIN_TRÅD_KLASS r = new DIN_TRÅD_KLASS(serverSocket.accept()); 
    r.start();
}

Anropen till servern kommer via ett "uttag", en socket. Denna socket anger en port på datorn som ditt program ska lyssna på. Ditt program kommer i princip be operativsystemet att vidarebefodra alla anrop med detta portnummer till ditt program. 

Nätverksklasserna ligger i java.net du kan skapa din socket med:

//...
try {
    serverSocket = new java.net.ServerSocket(port); 
} catch (IOException e) {
   // lämpligt felmeddelande ...
   // och kanske hoppa ur: 
   //System.exit(1);
}

För varje tråd ...

Skapa en trådklass som tar hand om ett specifikt anrop. Låt klassen ärva från Thread.

public class DIN_TRÅD_KLASS extends Thread{

Skriv en konstruktor som tar en Socket som parameter (se konstruktoranrop ovan) och sätter en privat medlemsvariabel.

Trådklassen ska ha en metod public void run() som kommer att anropas efter att r.start() körts (se ovan). 

Börja med att skriva ut en spårutskrift i run(). 

// Print address + port
System.out.println ("Connection from : " + 
                     socket.getInetAddress().getHostAddress() + ':' +
                     socket.getPort());	

För att läsa in värden från porten kan man använda BufferedReader. 

BufferedReader in = new BufferedReader
    (new InputStreamReader
     (socket.getInputStream()));

och för att skriva/skicka värden på nätverket kan man använda en PrintWriter. 

PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

Man läser och skriver på samma sätt som om det vore från tangentbordet. Exempel:

inputLine = in.readLine();
out.println("Calculating: " + inputLine);

Klienten

Skriv ett nytt java program som ska anropa servern. Du kan använda samma verktyg Socket, PrintWrite och BufferedReader igen. Porten måste vara samma som servern lyssnar på. Adressen till servern kan vara localhost eller 127.0.0.1 tills vidare eftersom vi kör båda programmen på samma maskin.

try {
    socket = new Socket(adress, port); 
    out = new PrintWriter(socket.getOutputStream(), true);
    in = new BufferedReader(new InputStreamReader
                            (socket.getInputStream()));
} catch (UnknownHostException e) {
    // ...
} catch (IOException e) {
    // ...

Skriv lite testlogik som skickar något som användaren matar in från tangentbordet till servern och sedan skriver ut vad servern svarar. 

BufferedReader stdIn = new BufferedReader
    (new InputStreamReader(System.in));
String userInput = stdIn.readLine();      
out.println(userInput);
System.out.println(in.readLine()); 

Testkör programmen

För att testköra programmen behöver du två terminalfönster. I det ena fönstret startar du servern. I det andra fönstret testkör du din klient. 

Det är många saker som kan gå fel. Porten kan vara upptagen. De första 1024 (av 65536) portarna är reserverade men det finns även andra portar som kan vara upptagna. När du avbryter servern (tryck [ctrl]-c) så kan det ta ett tag innan operativsystemet avregistrerar porten.

Labbuppgift

Skriv en klient som interaktivt frågar efter ett matematiskt uttryck. Därefter skickas uttrycket till servern. Servern ska kunna räkna ut ett svar och skicka tilbaka svaret samt en (fiktiv kostnad) på vad det kostat.

Implementera rekursiv medåkning i labb 4 så att man kan skicka komplicerade matematiska uttryck t.ex. 3+4*5*(2-1) eller "1 - 2 + 3". Se även slide 83 (sida 21) i Kjells anteckningar.

Klienten ska också fungera utan interaktion om man på kommandoraden anger extra argument, ett av dem ska vara det matematiska uttrycket. Tänk på att mellanslag tolkas, man kan kräva att användaren skriver det matematiska uttrycket inom citatecken "1 - 2 + 4" så att det skickas som ett argument till programmet.

Krav på servern

  • Servern ska skicka en bekräftelse till klienten när ett matematiskt uttryck mottagits
  • Server ska räkna ut svaret matematiskt med prioritetsordning t.ex. ska 3+2*4 evalueras till 11
  • Server ska skicka en kostnad baserat på det matematiska uttryckets komplexitet (valfri tolkning) men ska även ta hänsyn till vilken ip-adress som frågat och dess frågehistorik

Krav på klienten 

Klienten ska kunna köras interaktivt. Det räcker om det är ett terminalprogram (som i lab 1). Det ska vara självförklarande att köra programmet. Kostnader (med påslag) ska redovisas för användaren. 

Klienten ska även kunna köras utan interaktion genom att ange det matematiska uttrycket på kommandoraden. T.ex. 

  java Dinklient 127.0.0.1 "1 - 2 + 3 * 4"

Frivillig fortsättning (ej betygshöjande)

Skriv ett webbgränssnitt som kan anropa din klient. Kopiera din java-klient till din public_html. Skriv ett php-program i samma katalog döp det till calc.php. Man kan blanda html-kod och php-kod på följande sätt:

<h1>Räknaren</h1>

<?php
 $viktigvariabel = "Eva";
 echo "Adam och " . $viktigvariabel . "<p/>";
?>

<p/>
slut

Skriv följande php-kod som anropar din javaklient. 

   $uttryck = '12+12';
   $commandline = 'java DITTKLIENTPROGRAM IP_DÄR_SERVERN_KÖRS  PORT "' . $uttryck .  '" 2>&1';
   
   $handle = popen($commandline, 'r');
   echo "'$handle'; " . gettype($handle) . "<p/>\n";
   $read = fread($handle, 2096);
   echo $read;

Webbprogrammet kommer inte att på samma maskin som dit program. För att ta reda på vilken ip-adress din maskin har (där du startar server) kan du använda ifconfig -all eller uname -a på mac/unix. I windows öppnar du ett terminalfönster ([windows-R] cmd [retur]) och skriver ipconfig /all.

När du fått php-scriptet att fungera skapa en ny html-fil och skapa där ett formulär. 

<h1>Räknaren</h1>

 <FORM name=input action="http://www.csc.kth.se/~DINLOGIN/calc.php" method="get">
    <P>
    Räkna ut 
    <INPUT name="uttryck" type="text"><BR>
    </P>
    <INPUT type="submit" value="Submit" />
 </FORM>

Formuläret knyts till ditt skript på första raden. När man trycker på submit-knappen skickas värdet i textfältet till ditt php-skript. Det går att se i urlen:

http://www.csc.kth.se/~DITTLOGIN/calc.php?uttryck=6767

För att plockat ut värdet i php-scriptet skriver du:

$uttryck = $_GET['uttryck'];

Slutför och snygga till webbgränssnittet till din räknare.

Lärare Vahid Mosavat skapade sidan 14 januari 2015

Lärare Vahid Mosavat ändrade rättigheterna 17 januari 2015

Kan därmed läsas av alla och ändras av lärare.