java web course

Upload: loredana-pop

Post on 05-Feb-2018

259 views

Category:

Documents


1 download

TRANSCRIPT

  • 7/21/2019 Java Web course

    1/58

    139

    4. COMUNICAII JAVAFOLOSIND SOCKET

    4.1. Prezentarea generala pachetului java.net

    4.1.1. Principalele clase

    Acest pachet reprezint o infrastructur puternic i flexibil deprogramare n reea. Multe dintre clasele pachetului java.net fac parte dinaceastinfrastructur i nu sunt folosite direct n programele de aplicaii. Dinaceastcauzprezentm numai partea din structura pachetului care este directutilizabiln programe. ntreg pachetul este structurat pe un singur nivel; toateclasele descind direct din clasa Object, aa cum se vede n fig. 4.1.

    Object

    InetAddress

    DatagramPacket

    DatagramSocket

    Socket

    URL

    ServerSocket

    URLConnection Figura 4.1. Structura pachetului java.net

    Clasele pachetului sunt destinate srealizeze patru funciuni principale:

    gestiunea adreselor Internet; comunicarea prin UDP;

    comunicarea prin TCP;

  • 7/21/2019 Java Web course

    2/58

    140

    accesul la resursele Internet prin URL.

    Tabelul urmtor indicanalogii intuitive ale semnificaiilor acestor clase:

    InetAddress Purttor de adresInternet i IP

    DatagramPacket Pachet UDP - "plic purttor al unei scrisori"

    DatagramSocket Capt UDP - "csupotal"

    Socket Capt TCP - "telefon care face apel"

    ServerSocket Capt TCP - "telefon care ateaptapel"

    URL Purtror de adresspecificatprin URL

    URLConnectionO conexiune activla un obiect Internet:

    CGI, servlet, serviciu de reea etc.

    4.1.2. Cteva servicii standard de comunicaii

    Comunicaiile prin socket, indiferent dacsunt n Java sau n C/C++ saualt suport de dezvoltare, se fac dup principiul client - server. Cei doiprotagoniti care comunic pot fi elaborai n limbaje diferite, singura grij aproiectantului este sincont de reprezentrile datelor. Mai mult, ntr-o astfelde comunicaie este posibil ca unul dintre protagoniti s fie un serviciustandard, acesta fiind, de cele mai multe ori, partea de server.

    Proiectantul unei aplicaii distribuite poate s comunice cu astfel de

    servicii, cu condiia ca serviciul dorit sfie activ pe maina int. Specificaiile(protocoalele) de comunicaie pentru serviciile standard sunt publice i suntdisponibile pe Internet sub forma unor RFC-uri (Request For Comments). Deasemenea, serviciile standard au asociate porturi standard de comunicare,precum i tipurile de socket (TCP, UDP) prin care comunic. Tabelul urmtorprezintcteva astfel de servicii:

    Serviciul

    distribuit

    Port

    asociatSocket RFC de descriere

    DayTime 13TCPUDP 867

    Time 37TCPUDP

    868

    Echo 7TCPUDP

    862

    SMTP(SimpleMail Transfer

    Protocol) server e-mail25 TCP

    821 (SMTP), 822(Mail Format),1521 (MIME),1869 (Extended SMTP)

    SSMTP (Security SMTP) 465

    POP3(Post OfficeProtocol), 110 TCP 1725, 1939

  • 7/21/2019 Java Web course

    3/58

    141

    Serviciul

    distribuit

    Port

    asociatSocket RFC de descriere

    e-mail pentru workstations

    SPOP3 (SecurityPOP3) 995

    FTP (File Transfer Protocol) 20 TCP959, 2228-securityextension

    TFTP (TrivialFile Transfer

    Protocol)69 UDP 1350

    Telnet23,*

    TCP 854

    SSH (Security SH) 22 TCP 1920

    HTTP (HyperText Transfer

    Protocol)80 TCP

    1945 (HTTP1.0),2068 (HTTP1.1)

    HTTPS HTTP over TLS

    (TransportLayer Security)443

    4.2. Gestiunea adreselor Internet: InetAddress

    Clasa reprezint descrierea unei adrese Internet i este folosit attpentru comunicare prin UDP ct i prin TCP. Prezentm mai jos principalelemetode ale acestei clase.

    public final class InetAddress extends Object {

    public static InetAddress getLocalHost()

    throws UnknownHostException;

    public static syncronized InetAddress getByName(String host)

    throws UnknownHostException;

    public static syncronized InetAddress[] getAllByName

    (String host)

    throws UnknownHostException;

    public String getHostName();

    public byte[] getAddress();

    }

    Aceast clas este final, nu are constructor public, n schimb are treimetode statice care ntorc instanieri de clase InetAddress.

    Metoda getLocalHost

    ntoarce o InetAddress pentru host-ul local. Metoda getByNamentoarce o InetAddresspentru maina indicatprin host, care este

    fie o adresInternet, fie o adres IP n notaia punctual. Metoda

  • 7/21/2019 Java Web course

    4/58

    142

    getAllByNamentoarce un tablou de obiecte InetAddresscu toateadresele care localizeazhost.

    Metoda getHostName

    ntoarce numele host-ului gazd, iar getAddressntoarce adresa IP nformbinar, ntr-un ir de 4 (patru) octei primul fiind cel mai semni-ficativ (reprezentare bigendian).

    n seciunile urmtoare vom prezenta exemple de utilizare a acesteiclase.

    4.3. Transmitera si recepionarea prin UDP

    Comunicarea prin UDP este adesea folositn comunicaii simple la careeste mai importantviteza i mai rar n cazurile cnd datele ce se transmit suntimportante. Utilizarea acestei comunicri n Java este asiguratde douclase:DatagramPacketi DatagramSocket.

    4.3.1. Clasa DatagramPacket

    Pachetele trimise prin protocolul UDP sunt descrise de clasa

    DatagramPacket, care gestioneazstructura pachetelor UDP, aa cum suntele definite n standarde [48]. Structura acestei clase, cu principalele metode,este urmtoarea:

    public final class DatagramPacket extends Object {

    public DatagramPacket(byte[] t, int lungt);

    public DatagramPacket(byte[] t, int lungt,

    InetAddress adresa, int port);

    public byte[] getData();

    public int getLength();public int getPort();

    public InetAddress getAddress();

    }

    Primul constructor este folosit pentru recepia unei datagrame. De aceea,lui i se precizeaz un tablou de byte t i o lungime maxim de recepionatlungt. Al doilea constructor este folosit pentru emisia unei datagrame. Seindic un tablou t de unde s se preia datele, lungimea lungt de transmis,InetAddressa destinatarului i portla care acesta ateapt.

    Cele patru metode sunt utile mai ales duprecepia unui pachet:

  • 7/21/2019 Java Web course

    5/58

    143

    Metoda getData ntoarce n tabloul de byte datele trimise/recepionate de pachet.

    Metoda getLength ntoarce lungimea informaiei utile trimise/recepionate n pachet.

    Metoda getPort ntoarce numrul portului de la care a emis expe-

    ditorul mesajului sau la care a primit destinatarul. Metoda getInetAddress ntoarce un obiect de tip

    InetAddresscare conine adresele Internet i IP ale expeditorului/receptorului.

    4.3.2. Clasa DatagramSocket

    Structura acestei clase este:

    public class DatagramSocket extends Object {

    public DatagramSocket() throws SocketException;

    public DatagramSocket(int port) throws SocketException;

    public void send(DatagramPacket p) throws IOException;

    public syncronized void receive(DatagramPacket p)

    throws IOException;

    public getLocalPort();

    public syncronized void close();

    }

    Primul constructor creeaz un obiect DatagramSocket cu ajutorulcruia se pot trimite pachete de pe orice port local disponibil.

    Metoda send

    Transmite pachetul specificat ca argument. Adresa i portul destinaietrebuie sfie deja trecute n pachet.

    Al doilea constructor creeazun obiect DatagramSocketcare ateap-tla portprimirea de pachete. Pentru a recepiona un pachet, trebuie creat unDatagramPacket cu un buffer pentru recepia mesajelor, dimensionat aa

    nct pachetul primit sncap. n caz contrar ultimii octei se vor pierde.

    Metoda receive

    Ateapt primirea unui pachet pe care l depune n obiectulDatagramPacketspecificat ca argument.

  • 7/21/2019 Java Web course

    6/58

    144

    Metoda getLocalPort

    Este utilpentru socket-ul care trimite pachete de la un port ales aleatorde nucleul sistemului de operare local.

    4.3.3. Exemple de comunicaii prin UDP

    4.3.3.1. Un talk simplu

    Programele care urmeaz permit purtarea unui dialog ntre doiprotagoniti, prin schimburi de pachete UDP, n maniera n care o face talk.Spre deosebire de talk, aici discuia se face disciplinat, unul dintre prota-goniti trimite o linie, ateaptsprimeasclinia de rspuns de la cellalt, apoi

    i trimite iari o linie .a.m.d. Cititorul poate uor sextindaceste programe

    ca spoatrealiza un talkveritabil: este suficient ca la fiecare capt screezedouthread-uri, unul care scrie i altul care citete. Mai mult, prin nite interfeegrafice potrivite, mpreuncu nite applet-uri, poate realiza un veritabil chat.

    Pentru fixarea ideilor, s presupunem c avem doi protagoniti numiiActivi Pasiv. Protagonistul Pasivateaptde la Activun prim mesajcare s porneasc dialogul. Protagonistul Activ ncepe dialogul i tot eltermin activitatea celor doi protagoniti atunci cnd transmite un mesaj care

    ncepe cu STOP.Iat mai jos un exemplu de astfel de dialog. n fig. 4.2 este fereastra

    Pasiv, lansatpe maina nessie, iar n fig. 4.3 este fereastra Activ, lansatpe maina florin. Dupschimbul a douperechi de mesaje, ActivcomandSTOP. Pentru o urmrire mai interesanta dialogului, fiecare linie se ncheie cudoutampile de timp: ale expeditorului i ale destinatarului. (Diferenele orarenu in de durata schimbului de pachete, ci de faptul ccele doumaini nu auceasurile sincronizate!)

    Figura 4.2. Fereastra Pasiv

  • 7/21/2019 Java Web course

    7/58

    145

    Figura 4.3. Fereastra Activ

    Implementarea este realizat cu ajutorul a trei clase. ClasasemnaturaTemporala creeaz un string care conine numele mainiilocale, data i ora exacta mainii locale. Cu ajutorul acestei clase sunt realizatetampilele de timp. Sursa acestei clase este prezentatn programul 4.1.

    import java.net.*;

    import java.util.*;

    public class semnaturaTemporala {

    public String semnaturaTemporala() {

    String buf=null;

    try {

    //obtine numele masinii localeString hostname =

    (InetAddress.getLocalHost()).getHostName();

    buf = hostname+" "+

    // Thread.currentThread().getThreadGroup()+"\t"+// Thread.currentThread()+"\t"+

    new Date();} // trycatch (UnknownHostException e) {

    e.printStackTrace();

    } // catchreturn buf;

    } // semnaturaTemporala.semnaturaTemporala} // semnaturaTemporala

    Programul 4.1. semnaturaTemporala.java

    La crearea string-ului hostname se vede o prim utilizare a claseiInetAddress. Prin getLocalHost se obine obiectul InetAddress almainii locale, iar apoi prin getHostNamese obine numele (adresa Internet)a mainii locale.

    Celelalte dou programe au foarte multe elemente similare. Prezentmmai nti sursele acestora (programele 4.2 i 4.3), dup care venim cucomentarii la ambele.

  • 7/21/2019 Java Web course

    8/58

    146

    import java.io.*;

    import java.net.*;

    public class PasivUDP {

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

    semnaturaTemporala st = new semnaturaTemporala();

    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

    DatagramSocket si = new DatagramSocket(2345); // Receptie la portul// local 2345

    DatagramSocket so = new DatagramSocket(); // EmisieDatagramPacket p;

    InetAddress activ;

    byte [] b;

    String linie;

    for ( ; ; ) { // ciclu de asteptare mesajeb = new byte[1000];

    p = new DatagramPacket(b, b.length); // Creeaza p cu 1000 locurisi.receive(p); // Recepteaza linie de la portul local 23435activ = p.getAddress(); // De la cine a venit?linie = new String(p.getData()); // Converteste p la stringlinie = linie.substring(0,p.getLength()); // Retine doar ce a

    // primitSystem.out.println("Activ: "+linie+"");

    if (linie.indexOf("STOP")==0)

    break;

    System.out.print("Pasiv? "); // Cere o linie

    linie = in.readLine(); // Citeste linialinie += "";

    b = linie.getBytes(); // Converteste linia la bytesp = new DatagramPacket(b, b.length, activ, 5432);

    // Pune linia, adresa si portul destinatarso.send(p); // Trimite pachetul spre portul 5432 al lui Activ

    } // forso.close();

    si.close();

    in.close();

    } // PasivUDP.main

    } // PasivUDPProgramul 4.2. PasivUDP.java

    import java.io.*;

    import java.net.*;

    public class ActivUDP {

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

    semnaturaTemporala st = new semnaturaTemporala();

    BufferedReader in = new BufferedReader(

  • 7/21/2019 Java Web course

    9/58

    147

    new InputStreamReader(System.in));

    DatagramSocket si = new DatagramSocket(5432); // Receptie la portul// local 5432

    DatagramSocket so = new DatagramSocket(); // EmisieDatagramPacket p;

    InetAddress pasiv =

    InetAddress.getByName((a.length==0)?"localhost":a[0]);

    byte [] b;

    String linie;

    for ( ; ; ) { // ciclu de asteptare mesajeSystem.out.print("Activ? "); // Cere o linielinie = in.readLine(); // Citeste linialinie += "";

    b = linie.getBytes(); // Converteste linia la bytesp = new DatagramPacket(b, b.length, pasiv, 2345); // Pune

    // linia, adresa si portul destinatarso.send(p); // Trimite pachetul spre portul 2345 al lui Pasivif (linie.indexOf("STOP")==0)

    break;

    b = new byte[1000];

    p = new DatagramPacket(b, b.length); // Creeaza p cu 1000 locurisi.receive(p); // Recepteaza linie de la portul local 5432linie = new String(p.getData()); // Converteste p la stringlinie = linie.substring(0,p.getLength()); // Retine doar ce a

    // primitSystem.out.println("Pasiv: "+linie+"");

    } // forso.close();

    si.close();

    in.close();

    } // ActivUDP.main} // ActivUDP

    Programul 4.3. ActivUDP.java

    Ambele citesc linii de la intrarea standard prin intermediul obiectului in.Prompterul Activ?, respectiv Pasiv? cere cte o nou linie. La captulcellalt, linia transmis este prefixat cu Pasiv: respectiv Activ: i esteurmatde tampilele de timp ale celor doi protagoniti.

    Fiecare dintre ele utilizeazcte dousocket:

    sicare ateaptpachete la un anumit port - 2345 la Pasivi 5432la Activ;

    sopentru trimiterea de pachete ctre cellalt.

    Pentru emisie ambele transformString- ul linie ntr-un ir de bytespe care l depune n pachetul p, n care mai pune adresa i portul destinatarului.

  • 7/21/2019 Java Web course

    10/58

    148

    Pentru recepie, ambele rezervcte un pachet de 1000 octei, din careextrage i transform n String ci octei a primit efectiv. Dup recepie,fiecare i extrage din pachetul p adresa expeditorului, ntr-un obiectInetAddress.

    4.3.3.2. Consultarea unui server time

    Programul care urmeaz este un client care consult serviciul standardtimeaflat pe un server care are activ acest serviciu. Dupcum am artat maisus, acest serviciu ascult la portul 37, att prin TCP ct i prin UDP. Pentrumoment, tratm problema pentru cazul UDP.

    Dacse consultRFC868, se va vedea cprotocolul dupcare un clientpoate consulta timpul server-ului este:

    Server-ul:Ateaptsfie contactat la portul 37.

    Clientul:

    Trimite server-ului un pachet vid la portul 37.

    Server-ul:

    Recepioneazacest pachet vid, reine adresa clientului i portul

    local de la care i-a trimis clientul pachetul vid. Server-ul:

    Trimite clientului, la adresa i portul reinute mai sus, un pachetcu patru octei. n aceti patru octei server-ul pune, n confor-mitate cu calendarul i ceasul lui, numrul de secunde scurse de la01.01.1900 ora 00:00:00 i pn la momentul curent. Cei patruoctei conin reprezentarea n ordinea bigendian, a acestui numrde secunde, privii ca i un ntreg frsemn.

    Clientul:Recepioneaznumrul de secunde.

    Proiectantul unui client time scris n Java trebuie s aib n vederedoulucruri:

    1. Clasa Date din pachetul java.util are un constructor carecreeazun obiect de tip Dataplecnd de la numrul de milisecundescurs de la 01.01.1970 ora 00:00.

  • 7/21/2019 Java Web course

    11/58

    149

    2. Java, n mod implicit, nu tie s lucreze cu ntregi fr semn. Deexemplu, tipul de date byteare plaja de reprezentare [-128, 127], ncod complementar.

    1. Primul neajuns se rezolv simplu: ntre cele dou date s-au scurs

    2208988800secunde (cine nu crede scalculeze!).

    2. Al doilea neajuns se poate rezolva fie citind cei patru octei cu metodareadUnsignedBytede la un obiect de tip DataInputStream, fieconvertind cei patru octei din pachet la un obiectByteArrayInputStream care privete fiecare octet ca un numr

    ntre 0 i 255. Indiferent de procedeu, conversia celor patru octei la unntreg lung se face prin schema lui Horner, deoarece Java NU permitesuprascrierea unei zone de memorie, aa cum permite C sau C++ prin

    construcia union! n 2.4.3.2, programul 2.9, am prezentat o bibliotecce realizeazastfel de conversii.

    n metodele de consultare a timpului care urmeazvom realiza conver-siile n mod diferit, pentru varietatea expunerii. n prima metod folosimmetoda ConvertBytes.getInt a bibliotecii 2.9, n a doua metod vomfolosi direct un ByteArrayInputStream , iar n a treia vom converti folo-sind readUnsignedByte. Evident, cititorul este liber sfoloseascoricaremodalitate de conversie dorete.

    Pentru a nu mai reveni ncodatasupra consultrii timpului, prezentmun program de consultare a unui server timecare are trei metode:

    timeUDP1care folosete un singur socket i un singur pachet pentruconsultarea timpului (i convertete prinConvertBytes.getInt);

    timeUDP2, puin mai "complicat" din raiuni didactice, carefolosete pentru consultare dousocket-uri i doupachete, cte unulpentru fiecare sens de comunicaie (i convertete prin

    ByteArrayInputStream); timeTCPcare folosete conexiunea TCP care va fi explicatntr-o

    seciune urmtoare (i convertete prin readUnsignedByte),

    n consecin vom folosi metoda ConvertBytes.getInt a acesteibiblioteci. Sursa este datn programul 4.4.

    import java.io.*;

    import java.net.*;

    import java.util.*;

  • 7/21/2019 Java Web course

    12/58

    150

    public class Time {

    // A se vedea RFC 868final long Sec_1900_1970 = 2208988800L; // numarul de secunde intre 1900

    // (RFC868) si 1970 (java.util)

    String timeUDP1(String host) throws Exception {

    DatagramSocket s;

    DatagramPacket p;

    Date c;

    long l;

    String h;

    byte [] b = new byte[4];

    p = new DatagramPacket(b, 0, InetAddress.getByName(host),

    37);

    s = new DatagramSocket();

    s.send(p); // Trimite la server un pachet vid (RFC868)p.setLength(4);

    s.receive(p); // Asteapta cei 4 octeti si-i pune in pachet

    h = (p.getAddress()).getHostName(); // Adresa masinii de unde a venit// pachetul se scoate din pachet

    s.close();

    Integer[] in = new Integer[1];

    ConvertBytes.getInt(p.getData(), 0, in);

    l = (long)in[0].intValue(); // l contine numarul de secunde de la 01:01:1900l -= Sec_1900_1970; // Numarul de secunde pana la 1970c = new Date(l*1000); // Creaza o data in milisecunde de la 1970return c.toString()+" "+h;

    } // Time.timeUDP1

    String timeUDP2(String host) throws Exception {DatagramSocket so, si;

    DatagramPacket po, pi;

    Date c;

    int portLocal;

    long l;

    String h;

    byte [] b = new byte[4];

    po = new DatagramPacket(b, 0, InetAddress.getByName(host),

    37);

    pi = new DatagramPacket(b, 4);

    so = new DatagramSocket();

    portLocal = so.getLocalPort();

    so.send(po); // Trimite la server un pachet vid (RFC868)so.close();

    si = new DatagramSocket(portLocal);

    si.receive(pi); // Asteapta cei 4 octeti si-i pune in pacheth = (pi.getAddress()).getHostName(); // Adresa masinii de unde a venit

    // pachetul se scoate din pachetsi.close();

    Integer[] in = new Integer[1];

    ConvertBytes.getInt(pi.getData(), 0, in);

    l = (long)in[0].intValue(); // l contine numarul de secunde de la 01:01:1900l -= Sec_1900_1970; // Numarul de secunde pana la 1970

  • 7/21/2019 Java Web course

    13/58

    151

    c = new Date(l*1000); // Creaza o data in milisecunde de la 1970return c.toString()+" "+h;

    } // Time.timeUDP2

    String timeTCP(String host) throws Exception {

    Socket s;

    DataInputStream in;

    Date c;

    long l;

    String h;

    s = new Socket(host, 37);

    h = (s.getInetAddress()).getHostName(); // Se stie deja adresa masinii// server time

    in = new DataInputStream(s.getInputStream()); // Pe in vin 4 octeti in// bigendian

    byte[] b = new byte[4];

    in.read(b);

    Integer[] i = new Integer[1];

    ConvertBytes.getInt(b, 0, i);l = (long)i[0].intValue(); // l contine numarul de secunde de la 01:01:1900in.close();

    s.close();

    l -= Sec_1900_1970; // Numarul de secunde pana la 1970c = new Date(l*1000); // Creaza o data in milisecunde de la 1970return c.toString()+" "+h;

    } // Time.timeTCP

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

    Time t = new Time();

    System.out.println(t.timeUDP1("linux.scs.ubbcluj.ro"));// Trebuie sa fie server time si sa asculte UDP

    System.out.println(t.timeUDP2("linux.scs.ubbcluj.ro"));

    // Trebuie sa fie server time si sa asculte UDP

    System.out.println(t.timeTCP("linux.scs.ubbcluj.ro"));

    // Trebuie sa fie server time si sa asculte TCP

    System.out.println((new Date())+

    " "+(InetAddress.getLocalHost()).getHostName());

    } // Time.main} // Time

    Programul 4.4. Time.java

    Fiecare dintre cele trei metode are ca parametru de intrare adresa mainiicare este server de time. Metoda mainle apeleazpe celelalte trei, dupcareafieazi ora mainii locale (a se vedea desincronizarea ceasurilor).

  • 7/21/2019 Java Web course

    14/58

    152

    4.3.3.3. Un alt exemplu de comunicaie prin UDP

    Exemplul care urmeazeste unul simplu:

    Un program server ateaptmesaje de la clieni i le afieazpe ieireastandard mpreuncu adresa i portul de expediie.

    Programul a fost publicat n [10]. Singura modificare fcuta fost folo-sirea unor metode Java nedepite (non deprecation) pentru conversia String tablou de bytes.

    Programul server DatagramRecv ateapt sprimeasc un mesaj demaximum 1024 caractere de la un client oarecare pe portul 9898. Mesajul esteprimit n spaiul rezervat pachet. Dupprimire, mesajul este afiat pe ieireastandard a server-ului, mpreuncu adresa clientului expeditor i cu portul pecare s-a expediat. Sursa acestui server este prezentatn programul 4.5.

    import java.io.*;

    import java.net.*;

    // Receptioneaza un mesaj prin UDP:// Textul mesajului este primit prin socket este afisat la iesire

    public class DatagramRecv {

    static final int PORT = 9898;

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

    byte[] b = new byte[1024];String mesaj;

    // Creaza un pachet gol unde sa receptionezeDatagramPacket pachet = new DatagramPacket(b, b.length);

    // Creaza socket care asteapta la portDatagramSocket s = new DatagramSocket(PORT);

    for(;;) {

    // Asteapta sosirea unei datagrames.receive(pachet);

    // Converteste continutul la un stringmesaj = new String(b, 0, pachet.getLength());

    // Afiseaza mesajul la iesireSystem.out.println("Receptionat de la: "+

    pachet.getAddress().getHostName()+":"+

    pachet.getPort()+":\n"+mesaj);

    }

    }

    }

    Programul 4.5. DatagramRecv.java

  • 7/21/2019 Java Web course

    15/58

    153

    Sursa clientului DatagramSendeste prezentatn programul 4.6.

    import java.io.*;

    import java.net.*;

    // Trimite un mesaj prin UDP:

    // Masina destinatie este primul argument al liniei de comanda// Textul mesajului este al doilea argument al liniei

    public class DatagramSend {

    static final int PORT = 9898;

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

    if (args.length !=2) {

    System.out.println("Utilizare java Masina Mesaj");

    System.exit(1);

    }

    // Obtine adresa Internet a masiniiInetAddress adresa = InetAddress.getByName(args[0]);

    // Converteste mesajul intr-un sir de bytesint lungime = args[1].length();

    byte [] mesaj = args[1].getBytes();

    // Initializeaza pachetul cu date si adresaDatagramPacket pachet = new DatagramPacket(

    mesaj, lungime, adresa, PORT);

    // Creaza socket si emite pachetul prin el

    DatagramSocket s = new DatagramSocket();s.send(pachet);

    }

    }

    Programul 4.6. DatagramSend.java

    4.4. Comunicare prin TCP

    4.4.1. Clasa Socket

    Obiectele de tip Socket sunt folosite att la nivel de client, ct i lanivel de server, pentru comunicare prin TCP cu partenerul. Structura acesteiclase este:

    public final class Socket extends Object {

    public Socket(String host, int port)

    throws UnknownHostException, IOException;

    public Socket(InetAddress adresa, int port)

  • 7/21/2019 Java Web course

    16/58

    154

    throws IOException;

    public InputStream getInputStream() throws IOException;

    public OutputStream getOutputStream() throws IOException;

    public int getLocalPort();

    public int getPort();

    public InetAddress getInetAddress();

    public syncronized void close() throws IOException;

    }

    La crearea unui socket, adresa mainii la distanpoate fi precizat fieprintr-un String ce conine adresa IP sau Internet, fie printr-un obiectInetAddresspregtit n prealabil. n plus, se indici portul de comunicaie.

    Metodele getInputStreami getOutputStream

    Sunt cele mai importante. Ele ntorc obiecte de tip InputStreamrespectiv OutputStream, prin intermediul crora se realizeazschimburile de octei ntre parteneri. n legtur cu aceste obiecte,trebuie s facem o precizare important: metodele de tip read (citiribinare cu i frinterpretare) ale acestor obiecte nu asigurcitirea neap-rat a tuturor octeilor de pe socket! De fapt, metoda read ntoarcenumrul de octei pe care a reuit s-i citeascefectiv!. De aceea, progra-matorul trebuie saibgrijsrepete citirea de pe socket atunci cnd nu

    a primit numrul de octei solicitat.

    Metoda getLocalPort

    ntoarce numrul portului local folosit de socket.

    Metodele getPorti getInetAddress

    ntorc respectiv portul de la distan la care este conectat socket-ul,respectiv obiectul InetAddressal partenerului de la distan.

    Aplicaiile care comunic la distane mari, ca i aplicaiile complexe isofisticate utilizeaztransmisia prin TCP. Perechile client-server pot fi ambelescrise n Java, dar este posibil, dup cum vom vedea printr-un exemplu nseciunea urmtoare, ca unii dintre protagoniti sfie scrii n alt limbaj.

  • 7/21/2019 Java Web course

    17/58

    155

    4.4.2. Clasa ServerSocket

    Obiectele de tip ServerSocketau rolul de a atepta i de a acceptacererile de conexiune de la clieni. Server-ul e ntiinat de stabilirea conexiuniiprin primirea unui obiect de tip Socket, prin intermediul cruia se va realiza

    comunicaia. Structura clasei ServerSocketeste urmtoarea:

    public final class ServerSocket extends Object {

    public ServerSocket(int port) throws IOException;

    public ServerSocket(int port, int nr) throws IOException;

    public Socket accept() throws IOException;

    public int getLocalPort();

    public InetAddress getInetAddress();

    public void close();}

    Se observc, la crearea unui obiect SeverSocket, se precizeazdoarportul de comunicaie. Dac el are valoarea 0, atunci se consider orice portliber. Parametrul nr din al doilea constructor stabilete lungimea maxim acozii cererilor de conexiune. Daco cerere vine ntr-un moment n care coadaeste plin, conexiunea e refuzat.

    Metoda acceptEste cea mai important. n momentul conectrii unui client, aceasta

    ntoarce un socket prin intermediul cruia se realizeazcomunicaia.

    Exemplele din seciunile urmtoare vor clarifica modul de comunicareTCP din Java.

    4.5. Exemple de comunicaii TCP

    4.5.1. Un talk simplu (TCP)

    Relum problema dialogului ntre doi protagoniti: Pasiv i Activ,problem enunat de noi n 4.3.3.1 i implementatprin UDP. Exact aceeaifuncionaliti le vom realiza prin comunicare TCP. Pentru aceasta, protago-nistul Pasivva avea rolul de server, iar Activrolul de client.

    Cele dousurse sunt prezentate n programele 4.:

  • 7/21/2019 Java Web course

    18/58

    156

    import java.io.*;

    import java.net.*;

    public class PasivTCP {

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

    semnaturaTemporala st = new semnaturaTemporala();

    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

    ServerSocket ss = new ServerSocket(2345);

    Socket s;

    BufferedReader sin;

    PrintStream sout;

    String linie;

    for ( ; ; ) { // ciclu de asteptare mesajes = ss.accept(); // S-a stabilit o conexiunesin = new BufferedReader(

    new InputStreamReader(s.getInputStream()));

    sout = new PrintStream(s.getOutputStream());for ( ; ; ) { // Ciclul de dialog in cadrul conexiunii

    linie = sin.readLine();

    System.out.println("Activ: "+linie+"");

    if (linie.indexOf("STOP")==0)

    break;

    System.out.print("Pasiv? "); // Cere o linielinie = in.readLine(); // Citeste linialinie += "";

    sout.println(linie); // Trimite linia la client

    } // for conexiunebreak;} // for acceptsout.close();

    sin.close();

    in.close();

    s.close();

    ss.close();

    } // PasivTCP.main} // PasivTCP

    Programul 4.7. PasivTCP.java

    import java.io.*;

    import java.net.*;

    public class ActivTCP {

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

    semnaturaTemporala st = new semnaturaTemporala();

    BufferedReader in = new BufferedReader(

    new InputStreamReader(System.in));

    Socket s = new Socket((a.length==0)?"localhost":a[0], 2345);

    BufferedReader sin = new BufferedReader(

  • 7/21/2019 Java Web course

    19/58

    157

    new InputStreamReader(s.getInputStream()));;

    PrintStream sout = new PrintStream(s.getOutputStream());

    String linie;

    for ( ; ; ) { // ciclu de asteptare mesaje

    System.out.print("Activ? "); // Cere o linielinie = in.readLine(); // Citeste linia

    linie += "";

    sout.println(linie); // Trimite liniaif (linie.indexOf("STOP")==0)

    break;

    linie = sin.readLine();

    System.out.println("Pasiv: "+linie+"");

    } // forsout.close();

    sin.close();

    in.close();

    s.close();} // ActivTCP.main

    } // ActivTCP

    Programul 4.8. ActivTCP.java

    Urmrind programul server, trebuie remarcat faptul cmetoda acceptntoarce, n momentul conectrii unui client, un obiect Socket. Acesta dinurmeste folosit pentru schimbul efectiv de octei dintre client i server. Mo-mentul conectrii este momentul n care clientul creeaz obiectul socket cu

    precizarea adresei server-ului i a portului la care acesta ateapt.Apoi mai trebuie remarcat faptul cdin obiectele socket, att cel de la

    client ct i cel de la server, se creeaz cte o pereche de obiecte pentruschimbul n cele dou sensuri. Plecnd de la obiectele ntoarse de metodelegetInputStream i getOutputStream, n acest exemplu am construitperechile de obiecte BufferedReader i PrintStream, care permitefectuarea uoarde schimburi de linii (tip String).

    Mai trebuie remarcat faptul cspre deosebire de UDP, aici se utilizeazexplicit numai un singur port, cel de la server. De asemenea, schimbul de linii

    ntre protagoniti se face ca i cum s-ar efectua operaii I/O locale!Lsm pe seama cititorului s compare cele dou implementri i s

    constate cimplemetarea TCP este mult mai simpl.

    4.5.2. O aplicaie rezumat la distan: RemoteDir

    Problema care se pune este [10]:

  • 7/21/2019 Java Web course

    20/58

    158

    Clientul i transmite server-ului numele unui director, presupus a fi pe

    server. Server-ul execut rezumatul acestui director i l transmite ca

    rspuns clientului.

    Vom implementa un server scris n Java i trei clieni: unul Javastandalone, un applet Java i un client scris n C. Server-ul ateapt s fie

    contactat la portul 8899.

    4.5.2.1. Programul ServerRemoteDir

    Programul 4.9 prezentsursa serverului.

    import java.io.*;

    import java.net.*;

    public class ServerRemoteDir extends Thread {public final static int PORT = 8899;

    protected ServerSocket socket_intalnire;

    // Creeaza socket-ul de intalnire si initializeaza thread.public ServerRemoteDir() {

    try {

    socket_intalnire = new ServerSocket(PORT);

    } // trycatch (Exception e) {

    e.printStackTrace();

    System.exit(1);

    } // catchthis.start();} // ServerRemoteDir.ServerRemoteDir

    // Corpul thread-ului server. La fiecare conectare se creaza// un obiect de tip Conectare (definit mai jos), care trateaza// conexiunea printr-un socket noupublic void run() {

    Socket socket_client;

    try {

    for (;;) {

    socket_client = socket_intalnire.accept();

    Connectare c = new Connectare(socket_client);

    } // for} // trycatch (Exception e) {

    e.printStackTrace();

    } // catch} // ServerRemoteDir.run

    // Initializare serverpublic static void main(String[] a) {

    new ServerRemoteDir();

    } // ServerRemoteDir.main

  • 7/21/2019 Java Web course

    21/58

    159

    } // ServerRemoteDir

    Programul 4.9. ServerRemoteDir.java

    Constructorul ServerRemoteDir creeaz doarserver_intalnire prin care se ateapt contactarea de ctre clieni, laportul 8899, fixat prin constanta PORT.

    Partea curent a acestui thread (metoda run) ateapt prin acceptcontactarea de ctre un client. n momentul conectrii se creeazun thread nou,obiect instan a clasei Conectare. Pentru instaniere se transmite obiectulsocket obinut la conectare.

    Sursa thread-ului care comunicdirect cu clientul care s-a conectat estedatn programul 4.10.

    import java.io.*;

    import java.net.*;

    // Clasa care defineste thread-ul de tratare a unei conexiuniclass Conectare extends Thread {

    protected DataInputStream in;

    protected DataOutputStream out;

    Socket client;

    // Initializeaza "fisierul" de socket si thread-ulpublic Conectare(Socket socket_client) {

    client = socket_client;

    try {in = new DataInputStream(client.getInputStream());

    out = new DataOutputStream(client.getOutputStream());

    } // trycatch (Exception e) {

    e.printStackTrace();

    return;

    } // catchthis.start();

    } // Conectare.Conectare

    // Furnizeaza serviciulpublic void run() {final String NL = System.getProperty("line.separator");

    try {

    // Citeste lungimea si numele directoruluiint nr_oct = in.readInt();

    System.out.println(nr_oct);

    byte[] b = new byte[nr_oct];

    in.read(b);

    String director = new String(b);

    System.out.println(director);

    File f = new File(director);

  • 7/21/2019 Java Web course

    22/58

    160

    if (f.isDirectory()) {

    // Obtine rezumatul si-l face un string unicString[] rezumat = f.list();

    String s = new String();

    for(int i=0; i

  • 7/21/2019 Java Web course

    23/58

    161

    Nu este obligatoriu ca ambii protagoniti (client i server) saibcalimbaj gazdJava.

    Din raiuni de portabilitate sporit, majoritatea mesajelor din aplica-iile de comunicaii ncep cu ntregi care dau lungimea efectiv amesajului.

    4.5.2.2. Clientul standalone RemoteDir

    Sursa clientului standalone RemoteDir este prezentat n programul4.11.

    import java.io.*;

    import java.net.*;

    public class RemoteDir {public static final int PORT = 8899;

    public static void main(String[] a) {

    Socket s;

    String rezumat;

    try {

    s = new Socket(a[0], PORT);

    DataInputStream in =

    new DataInputStream(s.getInputStream());

    DataOutputStream out =

    new DataOutputStream(s.getOutputStream());

    byte[] b = a[1].getBytes(); // Nume director in sir de bytesout.writeInt(a[1].length()); // Trimite lungimeaout.write(b); // Trimite numele de directorint nr_oct = in.readInt(); // Citeste lungimeab = new byte[nr_oct];

    in.read(b); // Citeste rezumatulrezumat = new String(b);

    System.out.println(rezumat); // Afiseaza rezumatul} // trycatch (Exception e) {

    e.printStackTrace();

    } // catch} // RemoteDir.main

    } // RemoteDir

    Programul 4.11. RemoteDir.java

    Clientul primete n linia de comandadresa Internet a mainii ca primargument i numele de director ca al doilea argument.

  • 7/21/2019 Java Web course

    24/58

    162

    4.5.2.3. Clientul applet RemoteDirApp

    A doua variant de client este un applet. Sursa lui este prezentat nprogramul 4.12.

    import java.applet.*;import java.awt.*;

    import java.awt.event.*;

    import java.io.*;

    import java.net.*;

    public class RemoteDirApp extends Applet implements ActionListener

    {

    public static final int PORT = 8899;

    Socket s;

    DataInputStream in;

    DataOutputStream out;

    TextField director;String masina;

    TextArea rezumat;

    // Linia "director" va primi numele directorului// String-ul "masina" va fi preluat ca parametru HTML// Zona de date "rezumat" va afisa rezumatulpublic void init() {

    try {

    director = new TextField(

    "Aici se da numele directorului"); // Preia numele de directordirector.addActionListener(this);

    rezumat = new TextArea();rezumat.setEditable(false);

    this.setLayout(new BorderLayout());

    this.add("North", director);

    this.add("Center", rezumat);

    masina = this.getParameter("Masina"); // Citeste parametrul HTMLs = new Socket(masina, PORT);

    in = new DataInputStream(s.getInputStream());

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

    } // trycatch (Exception e) {

    e.printStackTrace();

    } // catch} // RemoteDirApp.init

    // Cand se da la director un text, evenimentul este// interceptat si linia este trimisa serveruluipublic void actionPerformed(ActionEvent e) {

    int n;

    byte[] b;

    if (e.getSource() == director) {

    try {

    b = (director.getText()).getBytes();

    out.writeInt(b.length); // Trimite lungimea

  • 7/21/2019 Java Web course

    25/58

    163

    out.write(b); // Trimite numele de directorn = in.readInt();

    b = new byte[n];

    in.read(b);

    rezumat.setText(new String(b));

    } // trycatch (Exception e2) {

    ;

    } // catch} // if

    } // RemoteDirApp.actionPerformed} // RemoteDirApp

    Programul 4.12. RemoteDirApp.java

    Clasa RemoteDirApp definete fereastra de acces prin intermediulcreia are loc dialogul dintre utilizator i client. Deoarece aici nu am putut

    prelua parametrii din linia de comand(applet-ul nu permite aa ceva) i nici nuputem afia pe ieirea standard, am adoptat o soluie mixt:

    adresa mainii server este preluatprintr-un parametru preluat dinfiierul sursHTML de lansare a clientului;

    numele de director este preluat printr-o component de tipjava.awt.TextField;

    rezumatul directorului este afiat ntr-o fereastr de tipjava.awt.TextArea.

    Partea din fiierul HTML necesarapelului acestui applet este prezentatn programul 4.13.

    RemoteDieApp

    Programul 4.13. RemoteDirApp.html

    n cadrul metodei init, activ la lansarea applet-ului, se configureazmai nti interfaa grafic. Apoi este preluat numele mainii din documentulHTML (tagul

  • 7/21/2019 Java Web course

    26/58

    164

    n linia de sus a interfeei grafice afiate de navigator (fig.4.4),utilizatorul scrie numele de director dorit. n momentul n care se tasteaz, se creeaz un obiect eveniment i este activat metodaactionPerformed. Aici se trimite server-ului lungimea numelui de directori apoi numele propriu-zis, dupcare ateaptrspunsul de la server. Rezumatul

    rspuns este afiat n zona TextAreade pe interfa.

    Figura 4.4. Interfaa graficgeneratde RemoteDirApp

    4.5.2.4. Client RemoteDir scris n C

    Al treilea client pentru ServerRemoteDir este elaborat n C subUnix. Sursa acestui program este:

    #include

    #include

    #include

    #include

    #include

    #include

  • 7/21/2019 Java Web course

    27/58

    165

    #include "ConvertBytes.cpp" // Pentru conversiile lungimilor!

    #define PORT_SERVER 8899

    #define DIRSIZE 8192

    main (int c, char *a[]) {

    char dir[DIRSIZE];

    int sd, i, l;

    struct sockaddr_in serv_addr;

    struct hostent *hp;

    sd = socket (AF_INET, SOCK_STREAM, 0);

    hp = gethostbyname (a[1]);

    memset ((char *) &serv_addr, 0, sizeof (serv_addr));

    serv_addr.sin_family = AF_INET;

    memcpy((char *) &serv_addr.sin_addr.s_addr,

    hp->h_addr_list[0], hp->h_length);

    serv_addr.sin_port = htons (PORT_SERVER);

    connect (sd, (struct sockaddr *)

    &serv_addr,sizeof (serv_addr));

    addInt(strlen(a[2]), dir, 0); // Converteste la int Javasend (sd, dir, 4, 0); // Trimite lungimeasend (sd, a[2], strlen (a[2]), 0); // Trimite numele

    for (i=0; i

  • 7/21/2019 Java Web course

    28/58

    166

    conversii am folosit biblioteca C descrisn 2.4.3, programul 2.10.

    2. n legturcu citirea de pe socket:

    Aa cum am precizat la descrierea clasei Socket, operaia read nuasigurcitirea tuturor octeilor de pe socket! Platforma Java are grijs-i buffer-izeze datele aa nct acest neajuns s fie transparent pentruprogram. Nu acelai lucru se poate spune despre C.

    n consecin, am preferat scitim octet cu octet. Mai nti am citit pernd cei patru octei ai ntregului lungime, iar dup conversia reprezentriilungimii am citit, cte unul, restul octeilor ntori de server.

    4.5.3. Folosirea ca partener a unor servicii standard

    Orice sistem de operare actual (Unix, Windows etc.), aa cum am artatmai sus (n 4.1.2), are operaionale o serie de servicii distribuite. Protocoaleleacestora sunt de regulindependente de platform, spre a putea comunica ntreele. n cele ce urmeazvom da cinci exemple de comunicaii n care unul dintreparteneri (fie clientul, fie server-ul) este un serviciu standard, iar al doileapartener este un program Java.

    4.5.3.1. Consultarea unui server time prin TCP

    Problema a fost prezentat n detaliu la conectarea time prin UDP,4.3.3.2. Prezentm mai jos doar funcia de obinere a timpului prin TCP, copiatdin programul 4.4.

    String timeTCP(String host) throws Exception {

    Socket s;

    DataInputStream in;

    Date c;

    long l;

    String h;s = new Socket(host, 37);

    h = (s.getInetAddress()).getHostName(); // Se stie deja adresa// masinii server time

    in = new DataInputStream(s.getInputStream()); // Pe in vin 4 octeti in// bigendian

    byte[] b = new byte[4];

    in.read(b);

    Integer[] i = new Integer[1];

    ConvertBytes.getInt(b, 0, i);

    l = (long)i[0].intValue(); // l contine numarul de secunde de la 01:01:1900

    in.close();

  • 7/21/2019 Java Web course

    29/58

    167

    s.close();

    l -= Sec_1900_1970; // Numarul de secunde pana la 1970c = new Date(l*1000); // Creaza o data in milisecunde de la 1970return c.toString()+" "+h;

    } // Time.timeTCP

    4.5.3.2. Autentificare folosind un server FTP

    n multe aplicaii se simte nevoia unui mecanism prin care un utilizator,de pe o anumit main, s fie autentificat printr-o parol. De regul, aceastactivitate nu este una prea simpli n plus este relativ nesigur: este posibil caun ru intenionat s"prind" parola!

    n cele ce urmeaz dm o soluie extrem de simpl i de elegant deautentificare - lsm pe seama server-ului de FTP s autentifice! Evident,metoda funcioneaznumai dacpe maina respectivexistun server de FTP.

    Invitm cititorul sconsulte RFC959 spre a vedea cum funcioneazFTPi care este, exact, protocolul de acces la un server FTP. Noi am extras pentruautentificare partea de protocol aferent:

    conectarea la portul 21; rspunsul la conectare; transmiterea spre server a unui nume de user (comanda user); rspunsul la aceastcomand; transmiterea parolei (comanda pass);

    rspunsul la aceastcomand.Mesajele transmise spre server sunt linii ASCII cu sintaxe prestabilite,

    iar rspunsurile server-ului FTP sunt linii ASCII care, n caz de succes, ncep cucte un anumit numr.

    Programul urmtor definete clasa AuthFTP, partea ei esenial fiindmetoda static (de clas) isFTPUser. Acesta din urm are trei parametri:adresa server-ului FTP, numele de utilizator i parola acestuia. Metoda ntoarcetruesau false, dupcum utilizatorul este autentificat sau nu.

    Programul mai conine i metoda main pentru a testa funciaisFTPUser. Sursa este prezentatn programul 4.15.

    import java.io.*;

    import java.net.*;

    public class AuthFTP {

    public static boolean isFTPUser(String host, String user,

    String password) {

    Socket socket = null;

    BufferedReader in = null;

    PrintStream out = null;

  • 7/21/2019 Java Web course

    30/58

    168

    String s;

    try {

    socket = new Socket(host, 21);

    in = new BufferedReader(

    new InputStreamReader(socket.getInputStream()));

    out = new PrintStream(socket.getOutputStream());

    s = in.readLine();

    if (s.indexOf("220") != 0)return(false);

    out.println("user "+user);

    s = in.readLine();

    if (s.indexOf("331") != 0)

    return(false);

    out.println("pass "+password);

    s=in.readLine();

    if (s.indexOf("230") != 0)

    return(false);

    return(true);

    } // trycatch (Exception e) {e.printStackTrace();

    return(false);

    } // catchfinally {

    try {

    if (out != null)

    out.close();

    if (in != null)

    in.close();

    if (socket != null)

    socket.close();

    in = null;

    out = null;

    socket = null;

    } // trycatch (Exception e) {

    } // catch} // finally

    } // AuthFTP.isUser

    public static void main(String a[]) {

    if (AuthFTP.isFTPUser(a[0], a[1], a[2]))System.out.println("Bine");

    else

    System.out.println("Rau");

    } // AuthFTP.main} // AuthFTP

    Programul 4.15. AuthFTP.java

  • 7/21/2019 Java Web course

    31/58

    169

    4.5.3.3. Autentificarea prin server POP3

    O soluie alternativde autentificare este aceea folosind server-ul POP3(evident dacacesta este operaional). Soluia este extrem de asemntoare cucea a lui AuthFTP. Invitm cititorul s consulte RFC1939 spre a vedea cum

    funcioneazPOP3. Partea de autentificare este extrem de asemntoare cu ceaa server-ului FTP. Singura deosebire constn faptul crspunsurile afirmativeale server-ului POP3 ncep cu string-ul "+OK".

    Sursa este prezentatn programul 4.16.

    import java.io.*;

    import java.net.*;

    public class AuthPOP3 {

    public static boolean isPOP3User(String host, String user,

    String password) {

    Socket socket = null;

    BufferedReader in = null;

    PrintStream out = null;

    String s;

    try {

    socket = new Socket(host, 110);

    in = new BufferedReader(

    new InputStreamReader(socket.getInputStream()));

    out = new PrintStream(socket.getOutputStream());

    s = in.readLine();

    if (s.indexOf("+OK") != 0)

    return(false);out.println("user "+user);

    s = in.readLine();

    if (s.indexOf("+OK") != 0)

    return(false);

    out.println("pass "+password);

    s=in.readLine();

    if (s.indexOf("+OK") != 0)

    return(false);

    return(true);

    } // trycatch (Exception e) {

    e.printStackTrace();

    return(false);

    } // catchfinally {

    try {

    if (out != null)

    out.close();

    if (in != null)

    in.close();

    if (socket != null)

    socket.close();

    in = null;

  • 7/21/2019 Java Web course

    32/58

    170

    out = null;

    socket = null;

    } // trycatch (Exception e) {

    } // catch} // finally

    } // AuthFTP.isUserpublic static void main(String a[]) {if (AuthPOP3.isPOP3User(a[0], a[1], a[2]))

    System.out.println("Bine");

    else

    System.out.println("Rau");

    } // AuthPOP3.main} // AuthPOP3

    Programul 4.16. AuthPOP3.java

    4.5.3.4. Un server de comenzi apelabil prin telnet

    Unul dintre clienii standard remarcabili este telnet. Pentru detalii,cititorul poate consulta RFC854, n care se descrie complet telnet. Acesta selanseazfolosind comanda:

    telnet adresaMasina [ port ]

    Dac port lipsete, atunci se conecteaz pe portul 23 i creeaz unclient terminal, de la care se poate dialoga cu sistemul de operare prin comenzi

    specifice lui (sistemului de operare).Aciunea clientului la alte porturi este specificportului/mainii la care

    se face telnet.n cele ce urmeazvom crea un server, l-am numit ServerTelnet, la

    care clienii sunt apeluri telnetpe portul 5656. Aciunea tandemului client(telnet) - ServerTelneteste urmtoarea:

    Clientul transmite server-ului o linie care trebuie sfie o comanddepe sistemul de operare pe care ruleazserver-ul.

    Server-ul preia linia respectiv. Lanseazcomanda n execuie sub forma unui proces extern mediului

    Java. Capteaz ieirea standard generatde execuia comenzii i o trimite

    clientului. Clientul afieazliniile pe consola lui

    Sursa ServerTelneteste prezentatn programul 4.17.

  • 7/21/2019 Java Web course

    33/58

    171

    import java.io.*;

    import java.net.*;

    public class ServerTelnet {

    public boolean telnet(BufferedReader in, PrintStream out)

    throws Exception {

    String s = in.readLine();Process p = (Runtime.getRuntime()).exec(s);

    p.waitFor();

    InputStream pin = p.getInputStream();

    byte[] b = new byte[1000];

    int n = pin.read(b);

    out.print("Iesirea comenzii \""+s+"\" este: "+

    ", Lungime: "+n+" caractere, Cod de retur: "+

    p.exitValue()+"\r\n");

    return p.exitValue()==0;

    } // ServerTelnet.telnet

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

    ServerTelnet st = new ServerTelnet();

    ServerSocket ss = new ServerSocket(5656);

    Socket s = ss.accept(); // S-a stabilit o conexiuneBufferedReader in = new BufferedReader(

    new InputStreamReader(s.getInputStream()));

    PrintStream out = new PrintStream(s.getOutputStream());

    st.telnet(in, out);

    out.close();

    in.close();

    s.close();

    ss.close();

    } // ServerTelnet.main} // ServerTelnet

    Programul 4.17. ServerTelnet.java

    Programul definete dou metode. Metoda telnet primete ca iparametri dou obiecte in i out, de tip BufferedReader iPrintStream de care se folosete pentru a citi linii respectiv a scrie linii.Practic metoda nu tie cu cine executoperaii I/O aceste obiecte.

    n cadrul metodei se citete o linie de la in care se presupune c e ocomand pentru SO-ul local. Cu ajutorul ei se creeaz un obiect de tipProcesscare lanseazcomanda n execuie.

    Se ateapt apoi terminarea execuiei, dup care se capteaz ieireastandard a rulrii comenzii, folosind n acest scop un obiect de tipInputStream.

    n sfrit, ieirea captatse pune pe outmpreuncu cteva informaiisuplimentare. Pentru a se vedea mai bine, liniile ieirii standard generate de

  • 7/21/2019 Java Web course

    34/58

    172

    execuia comenzii sunt puse ntre delimitatorii . Informaiilesuplimentare dau numrul de caractere al ieirii standard i codul de retur cucare s-a terminat execuia comenzii.

    Metoda main a programului creeaz socket-ul de ntlnire(ServerSocket) i ateaptprin acceptcontactarea de ctre client. Apoi,

    din obiectul socket ntors de accept sunt create cele dou obiecte I/O deschimb prin socket ntre client i server. Apoi lanseazmetoda telnet, dupcare nchide toate obiectele folosite.

    Pentru exemplificare, am lansat sub Windows2000Pro comanda:

    java ServerTelnet

    n acelai director am creat fiierul de comenzi echo.bat, prezentat nprogramul 4.18.

    @echo offecho Ii salut pe urmatorii:

    :IAR

    shift

    if "%0" == "" goto :STOP

    echo Salut %0

    goto :IAR

    :STOP

    Programul 4.18. echo.bat

    Apoi, de pe o main Linux am lansat un client telnet. Aspectulferestrei client, urmare a execuiei este prezentatn fig. 4.5.

    Figura 4.5. Fereastra client telnet

  • 7/21/2019 Java Web course

    35/58

    173

    4.5.3.5. Miniserver Web

    Comunicarea Web este o tehnologie clasic client/server. La nivelulinferior, Web comunic prin socket folosind protocolul TCP, iar mesajeleschimbate sunt linii de text. Server-ul Web ateapt cereri de la clieni fie la

    portul standard 80, fie la un alt port (de exemplu 8080 sau altul) fixat deadministratorul server-ului Web.La nivelul clientului se utilizeazun navigator (browser) Web, cum ar fi

    Mozilla, Internet Explorer, Netscape, Opera etc. Prin intermediul browser-ului, un utilizator Internet lanseazo cerere folosind o specificare URL.

    Navigatorul se conecteazla maina cu server-ul Web invocat prin URLi la portul solicitat. Din momentul conectrii, ntre cei doi protagoniti ncepeun dialog bazat pe protocolul, de nivelsuperiorindicat prin URL.

    n cele ce urmeazsimplificm lucrurile i presupunem c se folosetenumai protocolul HTTP (de fapt cel mai utilizat protocol), iar server-ul Weblivreaz navigatorului numai documente HTML. Pentru o documentarecomplet, invitm cititorul sconsulte RFC1945, RFC2068 sau RFC2616 spre avedea descrierea completa protocolului HTTP.

    n esen, prin HTTP comunicarea are loc n doi pai. Mai nti clientuliniiazo conexiune i trimite o cerere ctre server-ul Web, iar acesta i ntoarceun rspuns.

    O cerere HTTPconine trei componente:

    Prima linie indic metoda de cerere folosit, URL-ul resursei invo-

    cate iprotocolul/versiuneaacestuia. Urmtoarele linii, pn la prima linie goal (CRLF), conin antetul

    cererii. Restul liniilor, daceste cazul, conin corpulpropriu-zis al cererii.

    De exemplu, o cerere ar putea fi formatdin urmtoarele linii:

    POST /cgi-bin/Cgi.cgi HTTP/1.1

    Accept: text/plain, text/html, image/gif, image/x-xbitmap,

    image/jpeg

    Accept-Language: ro

    Accept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

    Host: florin:5555

    Connection: Keep-Alive

    Login=unUserOarecare&Password%3A=oParolaInClar

    Un rspuns HTTPconine trei componente:

    Prima linie indicprotocolul/versiuneaacestuia, codul de rspuns lacerere, descrierea rspunsului.

  • 7/21/2019 Java Web course

    36/58

    174

    Urmtoarele linii, pn la prima linie goal, conin antetul rspun-sului.

    Restul liniilor, dac este cazul, conin corpul propriu-zis al rspun-sului.

    De exemplu, un rspuns posibil ar putea fi:

    HTTP/1.1 200 OK

    Server: Microsoft IIS/4.0

    Date: Mon, 24 Nov 2003 11:07:32 GMT

    Content-type text/html

    Last Modified: Sun, 23 Nov 2003 11:07:32 GMT

    Content-Length: 77

    Prima pagina

    Salut

    Nu intrm n detalii privind protocolul HTTP. Precizm doar ctipurilede cereri folosite pot fi: GET, HEAD, POST, OPTIONS, PUT, DELETE,TRACE. Dintre aceste tipuri, ne vor interesa doar cererile de tip GET i POST.

    O cerere de tip GETeste cea mai simpl i probabil cea mai folositmetod de cerere. Datele efective ale cererii sunt de volum relativmic i sunt furnizate n cadrul URL-ului de cerere. Securitatea datelortransmise este practic inexistent, oricine poate s le citreasc din

    URL. De exemplu, dacn cererea de mai sus s-ar fi folosit metodaGET, atunci corpul cererii ar fi fost vid, iar prima linie ar fi fost:

    GET /cgi-bin/Cgi.cgi?Login=

    unUserOarecare&Password%3A=oParolaInClar HTTP/1.1

    O cerere de tip POST este folositpentru a transmite datele efective alecererii n corpul cererii. La acest tip de cerere volumul datelor nu estelimitat i existun grad oarecare de securizare a datelor transmise. n

    exemplul de cerere de mai sus am specificat o cerere POST.n cele ce urmeazvom defini un miniserver Web. Acesta va trata numai

    cereri de tip GET, iar cererile nu trebuie sconindect antet, nu i corp. ncazul n care din linia GET a cererii lipsete URL, se va considera implicitfiierul index.html aflat n directorul curent al miniserver-ului. ProgramulJava care joacrol de server Web l-am numit MiniHttpdi el se lanseaz:

    java MiniHttpd port

  • 7/21/2019 Java Web course

    37/58

    175

    Pentru a urmri mai uor funcionarea lui, din loc n loc am tipritmesaje explicative. Unele dintre acestea sunt prefixate de numrul curent alcererii, altele conin n plus informaii calendaristice.

    Pentru test, am depus n directorul curent al server-ului un singur fiier:Salut.html, cu urmtorul coninut:

    SalutSalut

    Pentru test, am specificat portul de ascultare 5555.Prima cerere s-a fcut cu Mozilla de pe maina Linux

    nessie.cs.ubbcluj.roi server-ul a fost indicat prin adresInternet. nfig. 4.6 este ilustratimaginea afiatde browser.

    Figura 4.6. Primul apel MiniHttpd

    Urmtoarea cerere, la fel cu prima, a fost fcutde pe aceeai maincu

    server-ul, care are Windows 2000 Pro. Navigatorul a fost tot Mozilla, iar adresaserver-ului a fost indicatprin adresIP. Imaginea afiatde browser este datn fig. 4.7.

    Figura 4.7. Al doilea apel MiniHttpd

    Ultima cerere a fost fcutde pe maina local, cu Internet Explorer inu s-a specificat nici un fiier. Pe browser a aprut rspunsul ilustrat n fig. 4.8.

    n fig. 4.9 sunt prezentate succesiunile de mesaje date de MiniHttpdla cele trei cereri de mai sus.

  • 7/21/2019 Java Web course

    38/58

    176

    Figura 4.8. Al treilea apel MiniHttpd

    Figura 4.9. Fereastra MiniHttpd

  • 7/21/2019 Java Web course

    39/58

    177

    Acum, dupce am vzut cum lucreazacest server, prezentm i textullui surs, n programul 4.19.

    import java.io.*;

    import java.net.*;

    import java.util.*;

    public class MiniHttpd {

    public static void main(String a[]) {

    if(a.length!=1) {

    System.out.println("Apel: java MiniHttpd port");

    System.exit(1);

    } // ifnew MiniHttpd(Integer.parseInt(a[0]));

    } // MiniHttpd.main

    public MiniHttpd(int port) {ServerSocket server;

    Socket socket;

    ThreadClient client;

    int nrCerere = 0;

    try {

    server = new ServerSocket(port);

    System.out.println(

    InetAddress.getLocalHost().getCanonicalHostName()

    +"("+InetAddress.getLocalHost().getHostAddress()+")"

    +":"+port+". "+new Date()+". MiniHttpd start ...\n");

    for ( ; ; ) {

    socket = server.accept(); // Asteapta conectarea de la un clientnrCerere++;

    System.out.println("! Sosit Cerere"+nrCerere+

    " de la: "+

    socket.getInetAddress().getHostName()+". "+new Date());

    client = new ThreadClient(socket, nrCerere); // Creaza un// thread pentru client

    client.start();

    } // for} // trycatch(Exception e) {

    e.printStackTrace();} // catch

    } // MiniHttpd.run} // MiniHttpd

    class ThreadClient extends Thread {

    Socket socket;

    PrintStream out;

    BufferedReader in;

    int nrCerere;

  • 7/21/2019 Java Web course

    40/58

    178

    public ThreadClient(Socket socket, int nrCerere) {

    this.socket = socket;

    this.nrCerere = nrCerere;

    } // ThreadClient.ThreadClient

    public void run() {

    String cerere;

    try {

    out = new PrintStream(socket.getOutputStream());

    in = new BufferedReader(

    new InputStreamReader(socket.getInputStream()));

    for ( ; ; ) {

    cerere = in.readLine();

    if (cerere==null)

    break;

    if (cerere.length()==0)

    break;

    System.out.println("Cerere"+nrCerere+": "+cerere);

    serveste(cerere);} // for cerereSystem.out.println("! Sfarsit Cerere"+nrCerere+"\n");

    in.close();

    out.close();

    socket.close();

    } // trycatch (Exception e) {

    e.printStackTrace();

    } // catch} // ThreadClient.run

    void serveste(String cerere) {

    File file;

    DataInputStream dis;

    int n;

    byte[] b = null;

    if(cerere.length()= 0)

    cerere = cerere.substring(cerere.indexOf(" ")+1);if(cerere.charAt(0)=='/')

    cerere = cerere.substring(1);

    if (cerere.indexOf(" ") >= 0)

    cerere = cerere.substring(0, cerere.indexOf(" "));

    if(cerere.equals(""))

    cerere = "index.html";

    try {

    file = new File(cerere);

    if(file.exists()) {

    dis = new DataInputStream(new FileInputStream(file));

    n = (int) file.length();

    // Accepta numai fisiere "scurte"

  • 7/21/2019 Java Web course

    41/58

    179

    b = new byte[n];

    dis.readFully(b);

    dis.close();

    } // if (then)else {

    System.out.println("*** Cerere"+nrCerere+

    " *** Fisierul \""+cerere+"\" nu exista pe server!");

    cerere = ""+

    "Pagina de eroare"+

    "HTTP/1.0 404 Not Found

    "+

    "Cerere"+nrCerere+": \""+cerere+"\":"+

    "nu exista pe server";

    b = cerere.getBytes();

    } // if (else)out.write(b);

    out.flush();

    } // try

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

    } // catch} // ThreadClient.serveste

    } // ThreadClient

    Programul 4.19. MiniHttpd.java

    Programul este compus din dou clase. Clasa MiniHttpd este clasaprincipal, conine metoda maini constructorul. Metoda mainpreia numrul

    de port i l transmite constructorului MiniHttpd. Constructorul, n partea deiniializare creeazobiectul de tip ServerSocketcare ascultla portul spe-cificat. Pe lngaceasta, la iniializare mai afieazun mesaj de start.

    Urmeazbucla principala server-ului, aceea n care ateaptconexiunide la clieni. La momentul unei conectri, prin intermediul metodei accept, seobine un obiect Socket pentru comunicarea cu clientul. Dup conectare seincrementeaz numrul curent al cererii i se creeaz un obiect de tipThreadClient. n fapt se creeaz un thread nou ce primete ca sarcincomunicarea cu clientul care s-a conectat. Dupcreare, obiectul creat este lansat

    n execuie, iar bucla se reia n ateptarea unei noi conexiuni.Clasa ThreadClient are un constructor i dou metode: run i

    serveste. Constructorul reine socket-ul prin care va comunica cu clientul inumrul efectiv al cererii.

    Metoda runa thread-ului ThreadClientdescrie partea principalacomunicrii cu un client. Mai nti creeaz obiectele in i out necesareschimburilor cu clientul. Apoi citete cererea de la client, linie cu linie. Afieazlinia curenta cererii, dupcare apeleaz metoda serveste, creia i trans-

  • 7/21/2019 Java Web course

    42/58

    180

    mite linia de cerere. Dup terminarea servirii, nchide obiectul, conexiuneasocket i tratarea clientului respectiv se termin.

    Metoda serveste a thread-ului ThreadClient reine din cereredoar linia cu tipul cererii i URL-ul invocat. Dac URL-ul este irul vid, sefixeazimplicit fiierul index.html.

    n cazul n care fiierul exist, coninutul lui este depus ntr-un ir debytes (am ales aceast cale limitativ pentru a simplifica programulMiniHttpd). n cazul n care fiierul nu exist, n irul de bytesse introduceun scurt document HTML care anuneroarea.

    Indiferent dac fiierul exist sau nu, metoda se ncheie cu scrierea pesocket (spre client), a irului de bytescare va ajunge la navigator.

    4.6. Accesul la resurse Internet prin URL

    4.6.1. Clasele URL i URLConnection

    4.6.1.1. Clasa URL

    Clasa URL, acronim de la Uniform Resource Locator, permite instan-ierea unor obiecte care identificresurse accesibile pe Web. O astfel de resurspoate fi un fiier, un director, sau un obiect mai complex, cum ar fi o cerereadresatunei baze de date sau unui motor de cutare.

    Reamintim c un URL are mai multe componente: protocolul folositpentru accesarea resursei (http, ftp, etc), maina pe care se gsete resursaaccesat, portul asociat serviciului care implementeaz protocolul folosit inumele resursei respective. Numele resursei, include i calea relativa acesteiala rdcina structurii de directoare a sistemului accesat.

    Aceste componente, dintre care portul este opional, sunt date ca para-metri n constructorul folosit pentru iniializarea unui obiect URL. Dacnu estefurnizat i argumentul port, se considerpentru acesta o valoare implicit (80direct, 8080 prinproxy), care corespunde serviciului http.

    Clasa URLconine metode care pot fi folosite pentru obinerea compo-nentelor unui URL. Astfel getFile permite obinerea numelui fiieruluiaccesat, getHost numele mainii, iar getPort numele portului la care s-arealizat conexiunea.

    Datele sau obiectele referite printr-un URL pot fi aduse din Internet ntrei moduri:

    1. direct, prin intermediul metodei getContent, a clasei URL;2. printr-un InputStream, obinut folosind metoda openStreama

    clasei URL;

  • 7/21/2019 Java Web course

    43/58

    181

    3. printr-o conexiune referitde un obiect URLConnection, obinutfolosind metoda openConnectiona clasei URL.

    Clasa URL este definitastfel:

    public final class URL extends Object {

    public URL(String protocol, String host,int port, String fisier) throws MalformedURLException;

    public URL(String protocol, String host, String fisier)

    throws MalformedURLException;

    public URL(String specificare) throws MalformedURLException;

    public URL(URL context, String host)

    throws MalformedURLException;

    public String getProtocol();

    public String getHost();

    public int getPort();

    public String getFile();

    public String getRef();

    public String toExternalForm();

    public final Object getContent() throws IOException;

    public final InputStream openStream() throws IOException();

    public URLConnection openConnection() throws IOException;

    }

    4.6.1.2. Clasa URLConnection

    Clasa abstractURLConnectioneste superclasa tuturor claselor careintermediazcomunicarea dintre o aplicaie sau applet Java i o resursInternet,identificatprintr-un URL. Astfel, instanele acestei clase pot fi folosite pentrua primi sau a transmite date resursei contactate. n general, crearea unei cone-xiuni la un anumit URL se realizeazn mai muli pai:

    1. n prima etap, se apeleazmetoda openConnectiona clasei URLAceast metod returneaz obiectul de conexiune de tipul

    URLConnection.2. Dup apel se manipuleaz parametrii implicai n conexiunea laresursa de la distan.

    3. n a treia etap, se apeleaz metoda connect a claseiURLConnection. Aceast metod permite stabilirea uneiconexiuni dintre aplicaia curenti resursa referitprin URL.

    4. Dupapelul connect, aplicaia poate interaciona cu obiectul de ladistanreferit prin URL.

  • 7/21/2019 Java Web course

    44/58

    182

    n cadrul acestui scenariu de interaciune, aplicaia poate accesacmpurile antetului conexiunii i coninutul resursei Internet, cu ajutorul unormetode de tip get, dintre care amintim getContent, getHeaderField,getInputStream i getOutputStream. Ultimele dou metode permitdeschiderea unui stream de intrare, respectiv a unui stream de ieire, prin care

    aplicaia curentpoate citi, respectiv transmite date obiectului de la distan.Printre parametri amintim dou flag-uri care precizeaz statutul deintrare i/sau ieire. O conexiune poate fi folosit pentru intrare i/sau pentruieire. Implicit flag-ul de intrare este true, iar flag-ul de ieire este false.

    Clasa URLConnection are multe cmpuri i metode. Iat numaicteva dintre ele.

    public final class URLConnection extends Object {

    public abstract void connect() throws IOException; // Deschide

    // comunicatiepublic URL getURL(); // Intoarce obiectul URL al conexiuniipublic int getContentLength(); // Intoarce lungimea coninutului resurseipublic String getContentType(); // Intoarce valoarea campul Content-type

    // al resurseipublic long getDate(); // Data creare resursa, milisec. de la 01.01.1970 00:00public long getLastModified(); // Ca mai sus, data ultimei modificari

    // Urmatoarele doua metode intorc obiecte stream de acces la resursapublic InputStream getInputStream() throws IOException();

    public getOutputStream();

    // Urmatoarele 4 metode manevreaza flagurile de intrare si de iesirepublic void setDoInput(boolean b);

    public boolean getDoInput();

    public void setDoOutput(boolean b);

    public boolean getDoOutput();

    }

    4.6.2. Exemplu de acces la o resursInternet

    Programul care urmeazprezintun exemplu de folosire a claselor URL(n mod indirect prin intermediul u.getURL())i URLConnection. Suntafiate o serie de informaii despre o resursdatprin URL. Sursa este prezen-tatn programul 4.20.

    import java.net.*;

    import java.io.*;

    import java.util.*;

  • 7/21/2019 Java Web course

    45/58

    183

    public class URLInfo {

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

    // Creeaza un URL la o resursa, deschide o conexiune cu acest URL,URL url = new URL(a[0]);

    URLConnection u = url.openConnection();

    // Afiseaza adresa URL si alte informatii despre eaSystem.out.println(u.getURL().toExternalForm() + ":");

    System.out.println("Tip continut: " + u.getContentType());

    System.out.println("Lungime continut: "+

    u.getContentLength());

    System.out.println("Ultima modificare: "+

    new Date(u.getLastModified()));

    System.out.println("Flagurile I/O. Input: "+u.getDoInput()+

    " Output: "+u.getDoOutput());

    // Citeste si afiseaza primele 10 linii de la URL.System.out.println("Primele 10 linii:");

    BufferedReader in = new BufferedReader(

    new InputStreamReader(u.getInputStream()));

    for(int i = 0; i < 10; i++) {String linie = in.readLine();

    if (linie == null) break;

    System.out.println(linie);

    } // for} // URLInfo.main

    } // URLInfo

    Programul 4.20. URLInfo.java

    Programul afieaz, pentru URL-ul transmis ca argunent n linia de

    comand, ase rnduri de informaii despre URL-ul respectiv (URL-ul, tipulconinutului, lungimea acestuia n octei, data i ora ultimei lui modificri, flag-urile de I/O) i primele zece linii sursale acestui URL.

    Fereastra de execuie este ilustratn fig. 4.10.

    Figura 4.10. Fereastra execuiei URLInfo

  • 7/21/2019 Java Web course

    46/58

    184

    4.7. CGI i comunicaii prin URLConnection

    4.7.1. Tehnologia CGI

    Tehnologia CGI, acronim de la Common GatewayInterfaceeste una din

    cele mai vechi interfae standard de comunicare dintre o aplicaie program i unclient Web, prin intermediul unui server Web. Astfel, server-ul Web transmitecererea clientului, aplicaiei respective. Aceasta proceseazcererea i transmiterezultatul napoi la server-ul Web, care la rndul su, forward-eazrspunsul laclientul care a lansat cererea.

    Cnd utilizatorul solicito paginWeb, server-ul, ca rspuns, i trimitenapoi pagina respectiv. Dar dacutilizatorul completeazun formular HTML,server-ul transmite informaiile primite unui program CGI, care le proceseaz,dupcare trimite napoi la server un mesaj de confirmare. Un document HTML

    este un fiier text static, care i pstreazo stare constant. Pe de altparte, unprogram CGI este executat n timp real i genereaz n mod dinamic, undocument HTML.

    Un program CGI poate fi scris ntr-o diversitate de limbaje de progra-mare, cele mai populare fiind: C, C++, script-uri Perl, script-uri shell Unix,Visual Basic, AppleScript. Pare curios, dar Java lipsete din lista limbajelor dedezvoltare a programelor CGI. Motivul se va vedea n ultimele dou capitoleale prezentei lucrri (Servlet i JSP).

    Un program CGI este lansat n execuie de ctre programul daemon al

    server-ului Web (httpd). n documentul invocator al CGI se specificprintr-un URL locul unde este plasat programul CGI. Locul (locurile) destinateplasrii programelor CGI sunt stabilite de ctre administratorul server-ului Webi tot el stabilete drepturile de creare de programe CGI de ctre utilizatori [97,98, 100, 2].

    n momentul lansrii n lucru a unui program CGI, server-ul Webstabilete pentru acesta un context specific. n cadrul acestui context se fixeazvalorile unor variabile de mediu specifice CGI. Principalele variabile de mediufixate la lansarea unui CGI sunt:

    SERVER_NAME Numele sau adresa IP a server-ului Web

    SERVER_SOFTWARE Software-ul server-ului Web (de exemplu IIS sau Apache)

    SERVER_PROTOCOL Protocolul de comunicare

    SERVER_PORT Portul de ateptare

    REQUEST_METHOD Metoda de cerere (de exemplu GET sau POST)

    SCRIPT_NAME Calea i numele CGI (de ex. /cgi-bin/TestCgi.cgi

    DOCUMENT_ROOT Rdcina server-ului Web

  • 7/21/2019 Java Web course

    47/58

    185

    QUERY_STRING irul de cerere din URL (prin metoda GET, [86])

    REMOTE-HOST Numele mainii client

    REMOTE_ADDR Adresa IP a mainii client

    REMOTE_USER Numele utilizatorului client

    CONTENT_TYPE Tipul MIME al cererii (de exemplu text/html)

    CONTENT_LENGTH Lungimea (n octei) a datelor transmise n corpul cererii

    HTTP_USER_AGENT Numele browser-ului client

    HTTP_REFFERER URL-ul documentului accesat de client nainte de CGI

    Indiferent de limbajul de elaborare a CGI, trebuie precizatmodalitateade primire a informaiilor de ctre CGI de la formular i modalitatea de rspuns.

    Datele de intrare sunt primite de CGI sub forma unei linii de text.

    Programul trebuie spriveascaceastlinie ca:

    valoarea variabilei de mediu QUERY_STRING, dacprogramul CGIeste apelat prin metoda Get,[86, 85, 24];

    prima linie din fiierul de intrare standard, dacprogramul CGI esteapelat prin metoda Post, [86, 85, 24].

    Datele de ieire din CGI sunt tiprite de ctre CGI la ieirea lui standardi sunt tratate de server-ul Web n conformitate cu specificaiile HTTP [85, 23].

    De cele mai multe ori ieirea standard este un document HTML (sau orice alttip de document inteligibil n browser) care este trimis browser-ului (sau altuiclient Web) ca i rspuns.

    Dup cum se va vedea n exemplele care urmeaz, schimbul de datedintre CGI i client poate fi orice obiect, cu condiia s fie serializabil.Conexiunile care suportschimburi mai speciale, i care asigurun nivel maimare de secret al comunicaiei, sunt cele efectuate prin metoda Post.

    4.7.2. Transformarea unui ir printr-un CGI

    Aplicaia distribuiteste formatdin trei nivele (aa numitarhitecturthree-tier):

    1. Nivelul client, care furnizeaz, rnd pe rnd, ctre nivelul urmtor server-ul Web -, una sau mai multe linii de text care urmeaz a fitransformate.

    2. Nivelul server Web, aflat n general pe o altmaindect clientul.

    Acesta preia liniile furnizate de client, le transmite nivelului CGI,

  • 7/21/2019 Java Web course

    48/58

    186

    acesta le va transforma, le va ntoarce spre server-ul Web, care larndul lui le va comunica transformate clientului.

    3. Nivelul CGIcare executefectiv transformarea liniilor de text.

    Pentru descrierea plicaiei, programatorul trebuie simplementeze numaiclientul i CGI. Drept server Web l vom folosi pe cel de pe mainalinux.scs.ubbcluj.ro.

    4.7.2.1. Programul CGI upcase

    Construim un CGI care citete de la intrarea standard un ir de caractere.Dupce a terminat de citit intrarea standard, ntoarce acelai ir, n care toateliterele mici sunt transformate n litere mari. Sursa C a acestui CGI este datnprogramul 4.21.

    #include

    #include

    main () {

    char s[1000];

    int i;

    for(i=0; ;i++) {

    s[i] = getchar();

    if (s[i]==EOF)

    break;

    } // fors[i] = 0;

    for (i=0; i='a')&&(s[i]

  • 7/21/2019 Java Web course

    49/58

    187

    de linii i le timite ctre CGI. Apoi citete liniile pe care i le ntoarce CGI i ledepune pe ieirea standard. Sursa acestei aplicaii este datn programul 4.22.

    import java.net.*;

    import java.io.*;

    public class Stand2CGI {static final String NL = System.getProperty("line.separator");

    static public void main(String a[]) {

    URL url;

    URLConnection urlCon;

    DataOutputStream out;

    BufferedReader in;

    String s = "";

    byte b[];

    try {

    url = new URL(a[0]+"/cgi-bin/upcase.cgi");

    urlCon = url.openConnection(); // Deschide conexiuneaurlCon.setDoOutput(true); // permite si scriereaSystem.out.println("Conexiune la URL: "+

    url.toExternalForm());

    in = new BufferedReader(new InputStreamReader(System.in));

    out = new DataOutputStream(urlCon.getOutputStream());

    // Citeste liniile de la intrarea standard si le trimite la CGIfor ( ; ((s=in.readLine()) != null); ) {

    s += NL;

    b = s.getBytes();

    out.write(b);

    } // forout.close();

    // Creaza un obiect care va citi linii de la CGIin = new BufferedReader(

    new InputStreamReader(urlCon.getInputStream()));

    // Citeste liniile venite de la CGI si le afiseaza pe iesirea standardfor ( ; ((s=in.readLine()) != null); ) {

    System.out.println(s);

    } // forin.close();

    } // trycatch(Exception e) {

    System.out.println("Stand2CGI: "+e);} // catch

    } // Stand2CGI.main} // Stand2CGI

    Programul 4.22.Stand2CGI.java

    Rezultatul execuiei apare ca n imaginea din fig. 4.11.

  • 7/21/2019 Java Web course

    50/58

    188

    Figura 4.11.Rezultatul execuiei clientului Stand2CGI

    Singurul element care ni se pare demn de semnalat este faptul c laconexiune i se seteaz(pe true) flag-ul DoOutput.

    4.7.2.3. Un client applet Applet2CGI

    Documentul HTML prin care este apelat acest client va conine ninteriorul lui liniile care vor fi transmise CGI-ului. Fiecare astfel de linie faceobiectul unui tag

  • 7/21/2019 Java Web course

    51/58

    189

    Programul 4.23.Applet2CGI.html

    Sursa applet-ului este datn programul 4.24.

    import java.net.*;

    import java.io.*;

    import java.applet.*;

    import java.awt.*;

    public class Applet2CGI extends Applet {

    static final String NL = System.getProperty("line.separator");

    public void init() {

    URL url;URLConnection urlCon;

    DataOutputStream out;

    BufferedReader in;

    String s="", linie;

    byte b[];

    int i;

    TextArea raspuns = new TextArea();

    try {

    linie = getParameter("URL");

    url = new URL(linie+"/cgi-bin/upcase.cgi");

    s = "Conexiune la URL: "+url.toExternalForm()+NL;

    urlCon = url.openConnection(); // Deschide conexiuneaurlCon.setDoOutput(true); // Permite si scrierea in resursaout = new DataOutputStream(urlCon.getOutputStream());

    // Citeste liniile date ca parametri in HTML si le trimite la CGIfor (i=1; ((linie = getParameter("Linia" + i))!= null);

    i++) {

    linie += "\n";

    b = linie.getBytes();

    out.write(b);

    } // for// Creeaza un obiect care va citi linii de la CGI

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

    // Citeste liniile de la CGI si le depune in sfor (i=1; ((linie = in.readLine())!= null); i++) {

    s += linie+NL;

    } // forin.close();

    out.close();

    this.add(raspuns); // Adauga obiectul la appletthis.setVisible(true); // Fa applet-ul vizibilraspuns.setText(s); // Depune liniile de raspuns

    } // try

  • 7/21/2019 Java Web course

    52/58

    190

    catch(Exception e) {

    s = "AppletCGI: "+e;

    } // catch} // Applet2CGI.init

    } // Applet2CGI

    Programul 4.24. Applet2CGI.java

    Rezultatul execuiei este dat n fig. 4.12.

    Figura 4.12.Rezultatul execuiei applet-ului Applet2CGI

    4.7.3. Construcia unui contor de pagini Web

    Pentru construirea unui counter, folosim un program CGI i un appletcare s comunice cu acesta. CGI-ul ntreine un fiier binar de 4 octei careconine numrul ultimei consulri a unei anumite pagini. Numele acestui fiiereste obinut din URL-ul CGI-ului, din care se pstreazdoar literele i cifrelenumelui de CGI, iar toate literele mari sunt transformate n litere mici; la acestnume se mai adaugsufixul ".count". De exemplu, dacURL-ul este:

    http://www.cs.ubbcluj.ro/~florin/cgi-bin/counterCGI.cgi

    atunci fiierul ntreinut de CGI are numele:

    countercgicgi.count

  • 7/21/2019 Java Web course

    53/58

    191

    4.7.3.1. Iniializarea fiierului contor

    Programul 4.25 iniializeaz astfel de fiiere, prelund de la intrareastandard numele fiierului i valoarea iniial:

    #include #include

    main (int c, char *a[]) {

    int i, f;

    if (c != 3) {

    printf(

    "Apel: counterInit numeFisier valoareInitialaContor");

    exit(1);

    } // iff = open(a[1], O_CREAT|O_WRONLY|O_TRUNC, 0666);

    i = atoi(a[2]);

    write(f, &i, sizeof(int));close(f);

    } // main

    Programul 4.25. initializareContor.c

    Pentru a putea fi apelat de ctre CGI, acest fiier trebuie saibcel puindrepturile 0666!

    4.7.3.2. Programul CGI

    Acesta primete de la intrarea standard numele fiierului. Apoi ldeschide, citete valoarea curent, o incrementeaz, o rescrie la loc i nchidefiierul. Dup aceea trimite napoi rspunsul ctre apelatorul CGI-ului, nconformitate cu protocolul HTTP pentru transmiterea de text simplu. Rspunsulconst dintr-o linie (de maximum 10 caractere) care conine numai cifrelezecimale ce reprezintvaloarea curenta contorului.

    Textul sursal CGI este prezentat n programul 4.26.

    #include

    #include

    #include

    extern int errno;

    main (int c, char *a[]) {

    int i=-1, f;

    char s[256];

    fgets(s, 256, stdin); // Citeste numele fisieruluif = open(s, O_RDWR);

    // Deschide fisierul

  • 7/21/2019 Java Web course

    54/58

    192

    if (f > 0) {

    lockf(f, F_LOCK, 0); // Blocheaza fisierul pentru incrementareread(f, &i, sizeof(int)); // Citeste numaruli++; // Incrementeazalseek(f, 0, 0); // Repozitioneaza la inceputwrite(f, &i, sizeof(int));// Rescrie noul numar

    lockf(f, F_ULOCK, 0); // Deblocheaza fisierulclose(f); // Inchide fisierul} // ifelse

    perror("");

    printf("Content-type: text/plain\n\n%d\n", i); // Trimite numarul// la client

    } // main

    Programul 4.26. counterCGI.c

    Pentru cazul nostru, acest fiier executabil va fi fiierul:~/public_html/cgi-bin/counterCGI.cgi

    4.7.3.3. Applet-ul de apel al contorului

    Pentru a se putea vizualiza contorul de acces al paginii, se utilizeazunapplet foarte simplu. Textul sursal acestuia este dat n programul 4.27.

    import java.net.*;import java.io.*;

    import java.applet.*;

    import java.awt.*;

    import java.util.*;

    public class AppletCounterCGI extends Applet {

    static final String nonLitereCifre =

    " ,./?;':\"[]{}`~!@#$%^&*()_-+=|\\";

    public void init() {

    URL url;

    URLConnection urlCon;

    BufferedReader in;

    DataOutputStream out;

    StringTokenizer st;

    String s = "";

    byte b[];

    Label raspuns;

    try {

    url = new URL(this.getCodeBase().toString()+

    "cgi-bin/counterCGI.cgi");

    s = url.toString();

    s = s.substring(s.lastIndexOf("/"));

  • 7/21/2019 Java Web course

    55/58

    193

    st = new StringTokenizer(s, nonLitereCifre);

    s = "";

    while (st.hasMoreTokens()) {

    s += st.nextToken();

    } // whiles = s.toLowerCase();

    s += ".count";

    urlCon = url.openConnection(); // Deschide conexiuneaurlCon.setDoOutput(true); // Permite scriereaout = new DataOutputStream(urlCon.getOutputStream());

    b = s.getBytes();

    out.write(b);

    System.out.println(s);

    in = new BufferedReader( // Creeaza obiect ce va citi o linie din CGInew InputStreamReader(urlCon.getInputStream()));

    s = in.readLine(); // Citeste linia si o depune in sraspuns = new Label(s, Label.CENTER); // Depune liniathis.add(raspuns); // Adauga obiectul la appletthis.setVisible(true); // Fa applet-ul vizibilin.close();

    out.close();

    } // try

    catch(Exception e) {

    e.printStackTrace();

    } // catch} // AppletCounterCGI.init

    } // AppletCounterCGI

    Programul 4.27.AppletCounterCGI.java

    n pagina HTML, invocarea acestui applet se face folosind secvena:

    Numrul de apeluri va apare ca un obiect Label n centrul ferestreirezervate de navigator pentru applet.

    4.7.4. Istoricul consultrii unei pagini Web

    Vis-a-vis de o pagin Web, pare interesant de nregistrat o istorie aconsultrilor ei. Deci, pe lngnumrarea acceselor, ne propunem sreinem, lafiecare acces al paginii, momentul accesului (dupceasul mainii de pe care seacceseaz), momentul terminrii consultrii i, evident, adresa de la care s-anavigat.

  • 7/21/2019 Java Web course

    56/58

    194

    Noi prezentm un CGI i un applet pentru aceasta i lsm pe seamacititorului s reuneasc, eventual, contorizarea cu istoria. Dup cum se vavedea, momentele de start i de terminare a accesului sunt obinute de un applet.

    ntreaga contorizare s-ar putea simplifica dac se renun la momentele

    de timp ale mainii client, eventual dacn locul acestora s-ar folosi timpii depe maina server. n acest caz nu mai este necasar applet de invocare a CGI, iaradresa clientului se poate obine folosind variabilele de mediu REMOTE_HOSTi REMOTE_ADDRale procesului CGI.

    4.7.4.1. Programul CGI

    Programul CGI citete, prin metoda post, un ir de octei trimii deapplet-ul descrcat pe navigator. El scrie aceti octei la sfritul unui fiiernumit historyi mai scrie un caracter linie nou'\n'. Sursa acestui CGIeste datn programul 4.28.

    #include

    main () {

    int c;

    FILE *f;

    f = fopen("history", "a");

    for( ; ;) {

    c = getchar();if (c==EOF)

    break;

    putc(c, f);

    } // forc = '\n';

    putc(c, f);

    fclose(f);

    printf("Content-type: "+

    "text/plain\n\n");

    }// main

    Programul 4.28. history.c

    4.7.4.2. Applet-ul de acces

    Applet-ul de acces rescrie metodele initi destroy. n initobinemomentul de nceput i adresa mainii de pe care se navigheaz, iar ndestroy obine momentul de sfrit i trimite CGI-ului linia cu cele treiinformaii.

    Sursa applet-ului este datn programul 4.29.

  • 7/21/2019 Java Web course

    57/58

    195

    import java.net.*;

    import java.io.*;

    import java.applet.*;

    import java.awt.*;

    import java.util.*;

    public class AppletHistory extends Applet {

    static final String NL = System.getProperty("line.separator");URL url;

    URLConnection urlCon;

    DataInputStream in;

    DataOutputStream out;

    String start="", navigator="", masina="";

    byte b[];

    public void init() {

    try {

    masina = getParameter("URL");

    start = ""+new Date();

    navigator = InetAddress.getLocalHost().toString();} // trycatch(Exception e) {

    e.printStackTrace();

    } // catch} // AppletHistory.init

    public void destroy() {

    try {

    url = new URL(masina+"/cgi-bin/history.cgi");

    urlCon = url.openConnection(); // Deschide conexiuneaurlCon.setDoOutput(true);

    // Permite si scrierea in resursain = new DataInputStream(urlCon.getInputStream());out = new DataOutputStream(urlCon.getOutputStream());

    start = start+" "+(new Date())+" "+navigator;

    b = start.getBytes();

    out.write(b);

    out.close();

    in.close();

    } // trycatch(Exception e) {

    e.printStackTrace();

    } // catch} // AppletHistory.destroy

    } // AppletHistory

    Programul 4.29. AppletHistory.java

    De obicei, URL-ul la care se aflCGI-ul i fiierul historyse aflpeaceeai maincu pagina. Noi permitem ca CGI i fiierul spoatfi, eventualpe o altmain. Din aceastcauzdat n codul HTML de citare a applet-ului

  • 7/21/2019 Java Web course

    58/58

    se specific, printr-un tag