Programarea în reţea – Socket-uri

 

Programarea în reţea – Socket-uri 1

1. Scopul lucrării 1

2. Noţiuni preliminare. 1

3. Aplicaţie client-server cu server monofir 3

4. Aplicatie client-server cu server multifir 5

5. Server HTTP. 7

6. Trimiterea obiectelor prin socket-uri 10

7. Socket-uri neblocante. 11

Exerciţii 17

 

1. Scopul lucrării

           

Scopul acestei lucrări este insuşirea tehnicilor de programare în reţea în limbajul Java utilizând socket-uri.

 

2. Noţiuni preliminare

 

Calculatoarele conectate in reţea comunică  între ele utilizând protocoalele TCP (Transport Control Protocol) şi UDP (User Datagram Protocol) conform diagramei:

 

Figura 1. Nivelele de omunicare în reţea

 

Pentru realizarea unor programe care comunică in reţea în java, se utilizează clasele din pachetul java.net . Acest pachet oferă clasele necesare pentru realizarea unor programe de reţea independente de sistemul de operare.

 

In tabelul următor sunt prezentate principalele clase care sunt utilizate pentru construirea unor programe de reţea.

 

Class

Scop

URL

Reprezintă un URL

URLConnection

Returnează continutul adresat de obiectele URL

Socket

Crează un socket TCP

ServerSocket

Crează un socket server TCP

DatagramSocket

Crează un socket UDP

DatagramPacket

Reprezintă o datagrama trimisă printr-un obiect DatagramSocket

InetAddress

Reprezintă numele unui pc din reţea, respectiv IP-ul corespunzător

 

Java oferă două abordări diferite pentru realizarea de programe de reţea. Cele două abordări sunt asociate cu clasele:

-          Socket, DatagramSocket şi ServerSocket

-          URL, URLEncoder şi URLConnection

 

Programarea prin socket-uri reprezintă o abordare de nivel jos, prin care, două calculatoare pot fi conectate pentru a realiza schimb de date. Ca principiu de baza, programarea prin socketuri face posibilă comunicarea în mod full-duplex între client şi server. Comunicarea se face prin fluxuri de octeţi.

 

Pentru ca comunicarea se desfăşoare corespunzător, programatorul va trebui să implementeze un protocol de comunicaţie (reguli de dialog), pe care clientul şi serverul îl vor urma.

 

Identificare unui calculator în reţea

 

Orice calculator conectat la Internet este identificat in mod unic de adresa sa IP (IP este acronimul de la Internet Protocol). Aceasta reprezinta un numar reprezentat pe 32 de biti, uzual sub forma a 4 octeti, cum ar fi de exemplu: 193.226.5.33 si este numit adresa IP numerică. Corespunzătoare unei adrese numerice exista si o adresa IP simbolica, cum ar fi utcluj.ro.
De asemenea fiecare calculator aflat într-o reţea locala are un nume unic ce poate fi folosit la identificarea locala a acestuia.

 

Clasa Java care reprezinta notiunea de adresa IP este InetAddress. Pentru a construi un obiect se foloseşte comanda:

 

InetAddress address =InetAddress.getByName("121.3.1.2");

 

Pentru a vedea toate modurile în care pot fi construite obiecte de tip InetAddress studiaţi documentaţia acestei clase.

 

Un calculator are în general o singura legătura fizica la reţea. Orice informaţie destinata unei anumite maşini trebuie deci sa specifice obligatoriu adresa IP a acelei maşini. Insa pe un calculator pot exista concurent mai multe procese care au stabilite conexiuni în reţea, asteptând diverse informaţii. Prin urmare datele trimise către o destinaţie trebuie sa specifice pe lângă adresa IP a calculatorului si procesul catre care se îndreaptă informaţiile respective. Identificarea proceselor se realizează prin intermediul porturilor.

 

Orice aplicaţie care comunică în reţea este identificată în mod unic printr-un port, astfel încât pachetele sosite pe calculatorul gazdă să poată fi corect rutate către aplicaţia destinaţie.

 

Valorile pe care le poate lua un număr de port sunt cuprinse între 0 si 65535 (deoarece sunt numere reprezentate pe 16 biţi), numerele cuprinse între 0 si 1023 fiind însă rezervate unor servicii sistem, si, din acest motiv, nu se recomandă folosirea acestora.

           

Definitia socket-ului: Un socket reprezintă un punct de conexiune într-o reţea TCP\IP. Când două programe aflate pe două calculatoare în reţea doresc să comunice, fiecare dintre ele utilizează un socket. Unul dintre programe (serverul) va deschide un socket si va aştepta conexiuni, iar celălalt program (clientul), se va conecta la server şi astfel schimbul de informaţii poate începe. Pentru a stabili o conexiune, clientul va trebui să cunoască adresa destinaţiei ( a pc-ului pe care este deschis socket-ul) şi portul pe care socketul este deschis.

           

Principalele operaţii care sunt facute de socket-uri sunt:

- conectare la un alt socket

- trimitere date

- recepţionare date

- inchidere conexiune

- acceptare conexiuni

 

3. Aplicaţie client-server cu server monofir

             

Pentru realizarea unui program client-server se utilizează clasele ServerSocket şi Socket.

 

Programul server va trebui să deschidă un port şi să aştepte conexiuni. In acest scop este utilizată clasă ServerSocket. In momentul în care se crează un obiect ServerSocket se specifică portul pe care se va iniţia aşteptarea. Inceperea ascultării portuli se face apelând metoda accept(). In momentul în care un client s-a conectat, metoda accept() va returna un obiect Socket.

 

La rândul său clientul pentru a se conecta la un server, va trebui să creeze un obiect de tip Socket, care va primi ca parametri adresa serverului şi portul pe care acesta aşteaptă conexiuni.

 

Atât la nivelul serverului cât şi la nivelul clientului, odată create obiectele de tip Socket, se vor obţine fluxurile de citire şi de scriere. In acest scop se utilizeaza metodele getInputStream() şi getOuptuStream().

 

In listingul următor este prezentat programul server.

 

import java.net.*;

import java.io.*;

 

public class ServerSimplu {

  public static void main(String[] args) throws IOException{

 

    ServerSocket ss=null;

    Socket socket=null;

    try{

      String line="";

      ss = new ServerSocket(1900); //creaza obiectul serversocket

      socket = ss.accept(); //incepe asteptarea peportul 1900

      //in momentul in care un client s-a  conectat ss.accept() returneaza

      //un socket care identifica conexiunea

 

      //creaza fluxurile de intrare iesire

      BufferedReader in = new BufferedReader(

            new InputStreamReader(socket.getInputStream()));

 

      PrintWriter out = new PrintWriter(

            new BufferedWriter(new OutputStreamWriter(

              socket.getOutputStream())),true);

 

      while(!line.equals("END")){

        line = in.readLine(); //citeste datele de la client

        out.println("ECHO "+line); //trimite date la client

      }

 

    }catch(Exception e){e.printStackTrace();}

     finally{

      ss.close();

      if(socket!=null) socket.close();

     }

  }

}

 

 

Programul client este prezentat în listingul următor:

 

import java.net.*;

import java.io.*;

 

public class ClientSimplu {

 

  public static void main(String[] args)throws Exception{

    Socket socket=null;

    try {

    //creare obiect address care identifica adresa serverului

      InetAddress address =InetAddress.getByName("localhost");

    //se putea utiliza varianta alternativa: InetAddress.getByName("127.0.0.1")

   socket = new Socket(address,1900);

 

      BufferedReader in =

        new BufferedReader(

          new InputStreamReader(

            socket.getInputStream()));

      // Output is automatically flushed

      // by PrintWriter:

      PrintWriter out =

        new PrintWriter(

          new BufferedWriter(

            new OutputStreamWriter(

              socket.getOutputStream())),true);

 

      for(int i = 0; i < 10; i ++) {

        out.println("mesaj " + i);

        String str = in.readLine(); //trimite mesaj

        System.out.println(str); //asteapta raspuns

      }

      out.println("END"); //trimite mesaj care determina serverul sa inchida conexiunea

 

    }

    catch (Exception ex) {ex.printStackTrace();}

    finally{

      socket.close();

    }

  }

}

 

 

Pentru verificare se va starta serverul, după care se va starta clientul. 

 

4. Aplicatie client-server cu server multifir

 

Analizând programul server prezentat în secţiunea anterioarăm se observă că acesta poate servi doar un singur client la un moment dat. Pentru ca serverul să poată servi mai mulţi clienţi simultan, se va utiliza programarea multifir.

 

Ideea de bază este simplă, şi anume, serverul va aştepta conexiuni prin apelarea metodei accept(). In momentul in care un client s-a conectat şi metoda accept() a returnat un Socket, se va crea un fir de execuţie care va servi respectivul clientul, iar severul va reveni în aşteptare.

 

In programul următor este prezentat un server multifir – capabil de a servi mai multi clienţi simultan.

 

import java.io.*;
import java.net.*;
 
public class ServerMultifir 
{
               public static final int PORT = 1900;
               void startServer()
               {
                               ServerSocket ss=null;
                               try
                               {
                               
                               ss = new ServerSocket(PORT);
                               while (true)
                               {
                                              Socket socket = ss.accept();
                                              new TratareClient(socket).start();
                               }
                               
                               }catch(IOException ex)
                               {
                                              System.err.println("Eroare :"+ex.getMessage());
                               }
                               finally
                               {
                                              try{ss.close();}catch(IOException ex2){}
                               }
               }
 
               public static void main(String args[])
               {
                               ServerMultifir smf = new ServerMultifir();
                               smf.startServer();
               }
 
 
}
 
class TratareClient extends Thread
{
                 private Socket socket;
                 private BufferedReader in;
      private PrintWriter out;
                 TratareClient(Socket socket)throws IOException 
                 {
                              this.socket = socket;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                               out = new PrintWriter(
                                              new BufferedWriter(
new OutputStreamWriter( socket.getOutputStream())));
                 }
                 
                 public void run()
                 {
                 try {
                 while (true) 
                 {  
           String str = in.readLine();
           if (str.equals("END")) break;
           System.out.println("Echoing: " + str);
           out.println(str);
          }//.while
                 System.out.println("closing...");
                 } 
                 catch(IOException e) {System.err.println("IO Exception");} 
                 finally {
          try {
           socket.close();
               }catch(IOException e) {System.err.println("Socket not closed");}
      }
               }//.run
}
 

5. Server HTTP

           

In această sectiune este creat un server HTTP care poate răspunde la cereri GET. Functia main() din cadrul clasei HttpServer startaează un fir de execuţie. In cadrul acestui fir se instanţiază un obiect ServerSocket şi se incepe ascultarea portului 80, care este portul standard pentru protocolul HTTP.

 

In momentul în care apare o cerere (un client se conectează pe portul 80) metoda accept() va returna un obiect Socket. In continuare se crează un obiect PrecesRequest (care este de tip fir de excutie), care va primi ca parametru, obiectul Socket returnat de metoda accept(). După crearea obiectului ProcesRequest, serverul revine în aşteptare şi va putea servi alţi clienţi.

Clasa ProcesRequest implementează o versiune simplificată a protocolului HTTP. In cadrul constructorului clasei ProcesRequest se crează fluxurile de intrare \ ieşire, după care este startat firul de execuţie. In cadrul firului de execuţie este analizată cererea primită de la client , şi în cazul în care aceasta este o cerere validă de tip GET, atunci se va transmite către client resursa solicitată.

 

import java.io.*;

import java.net.*;

 

class HttpServer extends Thread

{

            //portul standard

            private final static int PORT = 80;

           

            private final String iniContext="c:/temp/ServerHTTP/webdocs";

            private boolean alive;

           

            private ServerSocket ss;

            //constructor

            HttpServer()throws Exception{

                        System.out.println("Start server http.");

                        ss = new ServerSocket(PORT);

                        alive=true;

                        start();

            }

           

            public void run(){

                        while(alive){

                                   

                                    //asteapta conexiuni

                                    try{

                                    System.out.println("Server asteapta...");

                                    new ProcesRequest(ss.accept(),iniContext);

                                               

                                    }catch(IOException e){System.err.println("EROARE CONECTARE:"+e.getMessage());}

                                    //..reia bucla de asteptare dupa ce am creat un fir pentru client

                        }

                        System.out.println("STOP SERVER");

            }

            public static void main(String[] args)throws Exception

            {

                        try{

                        new HttpServer();

                        }catch(Exception e){e.printStackTrace();}

            }

           

}

 

import java.net.*;

import java.io.*;

import java.util.*;

 

class ProcesRequest extends Thread

{

            private PrintWriter outStr;

            private BufferedReader inStr;

            private Socket s;

            private DataOutputStream dout;

            private String iniContext;

 

            ProcesRequest(Socket s, String iContext){

                        try{

                                    outStr = new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);

                                    inStr = new BufferedReader(new InputStreamReader(s.getInputStream()));

                                    dout = new DataOutputStream(s.getOutputStream());

                                    iniContext = iContext;

                                    this.s = s;

                                    start();

                        }catch(IOException e)

                        {System.err.println("EROARE CONECTARE: "+e.getMessage());}

            }

           

            public void run(){

                        try{

                                    String fileName=null;

                                    String request = inStr.readLine();

                                    System.out.print(request);

                                    if(request.lastIndexOf("GET")==0) fileName = interpretGET(request);

                                    else throw new Exception("BAU");

                                    byte[] data = readFile(fileName);

                                    dout.write(data);

                                    dout.flush();

                                                           

                        }

                        catch(IOException e){outStr.println("<HTML><BODY><P>403 Forbidden<P></BODY></HTML>");}

                        catch(Exception e2){outStr.println("<HTML><BODY><P>"+e2.getMessage()+"<P></BODY></HTML>");}

                        finally{

                                    try{s.close();}catch(Exception e){}

                        }

            }

           

            private String interpretGET(String rqst) throws Exception{

                        StringTokenizer strT = new StringTokenizer(rqst);

                        String tmp="";

                        String fileN=iniContext;

                        tmp=strT.nextToken();

                        if(!tmp.equals("GET")) throw new Exception("Comanda GET invalida .");

                       

                        tmp=strT.nextToken();

                        if((tmp.equals("/")) || (tmp.endsWith("/"))) {

                                    fileN = fileN+tmp+"index.htm";

                                    System.err.println("CERERE:"+fileN);

                                    return fileN;

                        }

                       

                        fileN = fileN+ tmp;

                        System.err.println("CERERE:"+fileN);

                        return fileN;

            }

           

            private byte[] readFile(String fileN) throws Exception{

                        fileN.replace('/','\\');

                        File f = new File(fileN);

                        if(!f.canRead()) throw new Exception("Fisierul "+fileN+" nu poate fi citit");

                        FileInputStream fstr = new FileInputStream(f);

                        byte[] data = new byte[fstr.available()];

                        fstr.read(data);

                        return data;

            }

}

 

Pentru verificarea programului anterior se va modifica variabila iniContextm din cadrul clasei HTTPServer, astfel încât aceasta să indice calea corectă catre contextul iniţial (directorul unde se află toate resursele pe care clientul le poate accesa).

 

 

6. Trimiterea obiectelor prin socket-uri

 

Mecanismul de serializare pune la dispoziţia programatorului o metodă prin care un obiect poate fi salvat pe disc şi restaurat atunci cand este nevoie. Tot prin acelaşi mecanism un obiect poate fi transmis la distanta catre o altă maşină utilizând socketurile.    

 

Pentru a putea serializa un obiect acesta va trebui să implementeze interfaţa Serializable.

 

Pentru scrierea şi citirea obiectelor serializate se utilizează fluxurile de intrare / ieşire : ObjectInputStream si ObjectOutputStream.

 

Listingul următor prezintă modul in care se poate serializa / deserializa un obiect.

 

import java.io.*;

import java.net.*;

 

public class SerialTest extends Thread{

 

      public void run(){

 

      try{

        ServerSocket ss = new ServerSocket(1977);

        Socket s = ss.accept();

        ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

        Pers p = (Pers)ois.readObject();

        System.out.println(p);

        s.close();

        ss.close();

      }catch(Exception e){e.printStackTrace();}

 

      }

 

  public static void main(String[] args) throws Exception{

 

        //trimite obiect prin socket

        (new SerialTest()).start();

      

        Socket s = new Socket(InetAddress.getByName("localhost"),1977);

        ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());

        Pers p = new Pers("Alin",14);

        oos.writeObject(p);

        s.close(); 

 

  }

}

 

class Pers implements Serializable{

  String nume;

  int varsta;

 

  Pers(String n, int v){

    nume = n; varsta = v;

  }

 

  public String toString(){

    return "Persoana: "+nume+" vasrta: "+varsta;

  }

}

           

Există situaţii în care în momentul in care se selveaza starea unui obiect prin serializare, nu se doreşte salvare tuturor starilor obiectului, respectiv nu se doreşte salvarea sau transmiterea anumitor parametri ai obiectului. Pentru a bloca serializarea unui atribut al unui obiect serializabil se utilizează cuvantul cheie transient.

 

7. Socket-uri neblocante

 

Versiunea Java 2 Standad Edition 1.4 introduce un nou mecanism de comunicare în reţea prin interemediul socket-urilor neblocante – acestea permit comunicarea între aplicaţii fără a bloca procesele în apeluri de metode destinate deschiderii unei conexiuni, citirii sau scrierii de date.

 

Soluţia clasică pentru a construi o aplicaţie server care deserveşte mai mulţi clienţi este de a utiliza tehnologia firelor de execuţie şi de a aloca câte un fir de execuţie pentru fiecare client deservit. Folosind tehnologia socket-urilor neblocante programatorul va putea implementa o aplicaţie server pentru deservirea clienţilor fără a fi nevoit să apeleze în mod explicit la fire de execuţie pentru tratarea cererilor clienţilor. În continuare v-or fi prezentate principiile de bază ale acestei tehnologii şi modul în care pot fi construite aplicaţii client şi aplicaţii server pe tehnologia socket-urilor neblocante.

 

Arhitectura unui sistem ce utilizează socketuri neblocante pentru comunicare este ilustraţă în figura următoare.

 

Arhitectură cu socketu-uri neblocante.

 

Principalele operaţii ce au loc în cadrul unei aplicaţii bazată pe această tehnologie sunt:

-          Clientul: trimite cereri către server

-          Serverul: recepţionează cereri

-          SocketChannel: permite transmiterea de date între client şi server

-          Selector: reprezintă un obiect de tip multiplexor şi este punctul central al acestei tehnologii. Acesta monitorizează socket-urile înregistrate şi serializează cererile sosite de la acestea, transmiţându-le către aplicaţia server.

-          Cheile reprezintă obiectele ce încapsulează cererile sosite de la clienţi.

 

 

 

Un algoritm general pentru a construi un server neblocant arată astfel:

 

create SocketChannel;
create Selector
associate the SocketChannel to the Selector
for(;;) {
  waiting events from the Selector;
  event arrived; create keys;
  for each key created by Selector {
    check the type of request;
    isAcceptable:
      get the client SocketChannel;
      associate that SocketChannel  to the Selector;
      record it for read/write operations
      continue;
   isReadable:
      get the client SocketChannel;
      read from the socket;
      continue;
   isWriteable:
      get the client SocketChannel;
      write on the socket;
      continue;
  } 
}

 

Implementarea serverului constă într-o buclă infinită în cadrul căreia selectorul aşteaptă producerea de evenimente. În momentul în care un eveniment s-a produs si o cheie a fost generată se verifică tipul acestei chei. Tipurile de chei posibile sunt:

-          Acceptable – este asociată evenimentului de cerere de conexiune de la un client

-          Connectable – este asociată evenimentului de acceptare de conexiune de către client

-          Readable – citire de date

-          Writable – scriere de date

 

Clasa Selector este responsabilă pentru menţinerea unui set de chei care pot fi active în timpul rulării programului server. În momentul în care un evenimet este generat de către un client, o cheie este construită.

 

Selector selector = Selector.open();

 

Pentru a demultiplexa datele şi a avea acces la evenimente trebuie construit un canal de comunicaţie care va trebui înregistrat în cadrul obiectului de tip selector. Fiecare canal de comunicaţie înregistrat va trebui să specifice tipul de evenimente de care este inetersat.

 

ServerSocketChannel channel = ServerSocketChannel.open();

channel.configureBlocking(false);

InetAddress lh = InetAddress.getLocalHost();

InetSocketAddress isa = new InetSocketAddress(lh, port );

channel.socket().bind(isa);

 

SelectionKey acceptKey = channel.register( selector, SelectionKey.OP_ACCEPT );

 

Un canal care citeşte şi scrie date va fi înregistrat în felul următor:

 

SelectionKey readWriteKey = channel.register( selector,
SelectionKey. OP_READ| SelectionKey. OP_WRITE );

 

Codul aplicaţiei server ce implementează comunicarea prin socket-uri nonblocante este listat mai jos:

 

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

import java.nio.channels.spi.*;

import java.nio.charset.*;

import java.net.*;

import java.util.*;

 

public class NonBlockingServer2 {

 

      public static void main(String[] args) throws Exception{

           

//          Create the server socket channel

            ServerSocketChannel server = ServerSocketChannel.open();

//          nonblocking I/O

            server.configureBlocking(false);

//          host-port 8000

            server.socket().bind(new java.net.InetSocketAddress("localhost",8000));

            System.out.println("Server waiting on port 8000");

//          Create the selector

            Selector selector = Selector.open();

//          Recording server to selector (type OP_ACCEPT)

            server.register(selector,SelectionKey.OP_ACCEPT);

           

//          Infinite server loop

           

            for(;;) {

            Thread.sleep(1000);

              // Waiting for events

              System.err.println("wait for event...");

              selector.select();

             

              // Get keys

              Set keys = selector.selectedKeys();

              Iterator i = keys.iterator();

              System.err.println("keys size="+keys.size());

              // For each keys...

              while(i.hasNext()) {

                 

                  // Obtain the interest of the key

                SelectionKey key = (SelectionKey) i.next();

 

                // Remove the current key

                i.remove();

               

                            

                // if isAccetable = true

                // then a client required a connection

                if (key.isAcceptable()) {

                  System.err.println("Key is of type acceptable");     

                  // get client socket channel

                  SocketChannel client = server.accept();

                  // Non Blocking I/O

                  client.configureBlocking(false);

                  // recording to the selector (reading)

                  client.register(selector, SelectionKey.OP_READ);

                  continue;

                }

 

                // if isReadable = true

                // then the server is ready to read

                if (key.isReadable()) {

                  System.err.println("Key is of type readable");

                  SocketChannel client = (SocketChannel) key.channel();

                 

                  // Read byte coming from the client

                  int BUFFER_SIZE = 32;

                  ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);

                  try {

                    client.read(buffer);

                   

                  }

                  catch (Exception e) {

                    // client is no longer active

                        client.close();

                       

                    e.printStackTrace();

                    continue;

                  }

 

                  // Show bytes on the console

                  buffer.flip();

                  Charset charset=Charset.forName("ISO-8859-1");

                  CharsetDecoder decoder = charset.newDecoder();

                  CharBuffer charBuffer = decoder.decode(buffer);

                  System.out.println(charBuffer.toString());

                  continue;

                }

               

               

              }

              System.err.println("after while keys size="+keys.size());

            }

      }

}

 

Condul aplicaţiei client ce foloseşte socketu-uri neblocante pentru comunicarea cu un server este listat mai jos:

 

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

import java.nio.channels.spi.*;

import java.nio.charset.*;

import java.net.*;

import java.util.*;

 

public class NonBlockingClient {

     

     

      public static void main(String[] args) throws IOException {

 

           

//          Create client SocketChannel

            SocketChannel client = SocketChannel.open();

 

//          nonblocking I/O

            client.configureBlocking(false);

 

//          Connection to host port 8000

            client.connect(new java.net.InetSocketAddress("localhost",8000));

 

//          Create selector

            Selector selector = Selector.open();

 

//          Record to selector (OP_CONNECT type)

            SelectionKey clientKey = client.register(selector, SelectionKey.OP_CONNECT);

 

//          Waiting for the connection

            while (selector.select(500)> 0) {

                 

              System.err.println("Start communication...");

             

              // Get keys

              Set keys = selector.selectedKeys();

              Iterator i = keys.iterator();

 

              // For each key...

              while (i.hasNext()) {

                SelectionKey key = (SelectionKey)i.next();

 

                // Remove the current key

                i.remove();

 

                // Get the socket channel held by the key

                SocketChannel channel = (SocketChannel)key.channel();

 

                // Attempt a connection

                if (key.isConnectable()) {

 

                  // Connection OK

                  System.out.println("Server Found");

 

                  // Close pendent connections

                  if (channel.isConnectionPending())

                    channel.finishConnect();

 

                  // Write continuously on the buffer

                  ByteBuffer buffer = null;

                  int x=0;

                  for (;x<7;) {

                        x++;

                    buffer =

                      ByteBuffer.wrap(

                        new String(" Client " + x + " "+x).getBytes());

                    channel.write(buffer);

                    buffer.clear();

                    try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}

                  }

                  channel.finishConnect();

                  client.close();

                }

              }

            }

            System.err.println("Client terminated.");

      }

}

 

Exerciţii

Importaţi în mediul Eclipse proiectul ce exemplifică noţiunile prezentate în acest laborator (link proiect).

Pachetul lab.scd.socket exemplifica construirea unor aplicatii server si client ce comunica utilizand protocolul TCP.

1)

 2)

 Pachetul lab.scd.datagrame exemplifica constuirea unor aplicatii server si client ce comunica utilizand protocolul UDP.

Pachetul lab.scd.broadcast exemplifica constuirea unor aplicatii server si client ce comunica utilizand protocolul UDP.

Pachetul lab.scd.serializare exemplifică mecanismul de serializare şi deserializare a obiectelor.

Pachetul lab.scd.net.httpexample prezinta modul in care poate fi construit in java un server HTTP. Aplicatia exemplu implementeaza partial protocolul HTTP, raspunzand la cereri de tip GET. Analizati modul de construire al aplicatiei, executati si testati aplicatia.

Pachetul lab.scd.net.url_http pezinta clasele din java.net ce pot fi utilizate pentru lucrul cu URL-uri.

Pachetul lab.scd.net.browser prezintă modul în care poate fi construit în java un browser de pagini html.