In aceasta lucrare de laborator vor fi
acoperite urmatoarele probleme:
- Programare OO: - Generalizarea si specializarea claselor.
- Mostenirea. Rescrierea codului (overriding)
- Socket-uri: - Incapsularea adreselor IP in Java (clasa InetAddress)
- Socket-uri pentru fluxuri TCP (clasa Socket) Introducere in socket-uri -link extern
- Socket-uri pentru servere TCP (clasa ServerSocket) Fluxuri (IO) - link extern
- Studiu de caz: Aplicatii
client-server bazate pe socket-uri TCP care folosesc mostenirea
Generalizarea reprezinta extragerea elementelor comune (atribute, operații și constrângeri) ale unui ansamblu de clase într-o nouă clasă mai generală numită superclasă (care reprezinta o abstracție a subclaselor ei).
Rezulta o ierarhie arborescenta in care arborii de clase sunt construiți pornind de la
Generalizarea semnifică
"este un" atunci cand un obiect dintr-o clasa din ansamblul
generalizat este in acelasi timp si obiect al superclasei, si de tip "este un fel de" atunci cand un
obiect dintr-o clasa din ansamblul generalizat este doar aproximativ si obiect
al superclasei (aproximatia venind din rescrierile codurilor operate in clasa
generalizata).
Generalizarea actioneaza in orientarea spre obiecte la doua niveluri:
- clasele sunt generalizari
ale ansamblurilor de obiecte (un obiect este de felul definit de o clasa),
- superclasele sunt
generalizari ale unor clase (obiectele de felul specificat intr-o clasa sunt in acelasi timp si de felul specificat in superclasa).
Orientarea spre obiecte (OO) presupune ambele tipuri de
generalizare, iar limbajele
orientate spre obiecte sunt acelea care ofera ambele mecanisme de generalizare. Limbajele care ofera doar
constructii numite obiecte (si eventual clase) se pot numi limbaje care lucreaza cu obiecte (si eventual clase).
Specializarea claselor reprezinta capturarea
particularităților unui ansamblu de obiecte nediscriminate ale unei
clase existente, noile caracteristici fiind reprezentate într-o nouă clasă mai specializată, denumită subclasă.
Specializarea usureaza
extinderea coerentă a unui ansamblu de clase,
sta la baza programării prin extindere
si reutilizare, noile cerințe fiind încapsulate în subclase care extind
funcțiile existente.
În elaborarea
unei ierarhii de clase, se cer diferite aptitudini sau competențe: capacitate de abstractizare,
independentă de cunoștințele tehnice, pentru identificarea superclaselor (pentru generalizare), experiență si cunoștințe aprofundate într-un domeniu particular,
pentru implementarea subclaselor
(pentru specializare).
Moștenirea este o
tehnică de generalizare oferită de
limbajele de programare orientate spre obiecte pentru a construi o clasă pornind de la una sau mai multe alte
clase, partajând atributele si
operațiile într-o ierarhie de clase.
In limbajul Java, orice clasa care nu extinde in mod explicit (prin mostenire) o alta clasa Java, extinde (prin mostenire) in mod implicit clasa Object (radacina ierarhiei de clase Java), clasa care contine metodele necesare tuturor obiectelor create din ierarhia de clase Java. Urmatoarele doua declaratii de clasa sunt echivalente:
|
class
NumeClasa { // urmeaza corpul clasei ... |
|
class
NumeClasa extends Object { // urmeaza corpul clasei ... |
Notatia UML pentru extinderea prin mostenire este o linie care uneste clasa extinsa (de
baza, superclasa) de clasa care extinde (subclasa),
linie terminata cu un triunghi in
capatul dinspre clasa de baza. Diagrama UML corespunzatoare codului Java anterior:
Printre metodele declarate in clasa Object este si toString(), metoda care are ca scop returnarea sub forma de String a informatiilor pe care le incapsuleaza obiectul caruia i se aplica aceasta metoda. In cazul claselor de biblioteca Java, metoda toString() returneaza ansamblul valorilor curente ale atributelor obiectului.
In cazul claselor scrise de programator, in mod implicit metoda toString() returneaza numele clasei careia ii apartine obiectul urmat de un cod alocat acelui obiect (hashcode). Implementarea implicita a metodei toString() este urmatoarea:
1 2 3 4 5 6 7 |
// Implementarea implicita a metodei
toString(), // mostenita de la clasa Object public String toString() { // (nu
returneaza continutul ci numele clasei si codul obiectului!) return getClass().getName()
+ "@" + Integer.toHexString(hashCode()); } |
In cazul in care programatorul doreste returnarea informatiilor incapsulate in obiect, trebuie specificat in mod explicit un nou cod (o noua implementare) pentru metoda toString(). Acest lucru se obtine adaugand clasei din care face parte acel obiect o metoda cu declaratia:
|
public String toString() { //
urmeaza corpul metodei ... |
metoda care se spune ca rescrie (overrides) codul metodei cu acelasi nume din clasa extinsa (in acest caz clasa Object).
Dupa adaugarea acestei metode, apelul toString() va conduce la executia noului cod, pe cand apelul super.toString() va conduce la executia codului din clasa extinsa (superclasa, in acest caz codul implicit din clasa Object).
Printre metodele declarate in clasa Object este si metoda equals(), metoda care are ca scop compararea continutului obiectului primit ca parametru cu continutul obiectului caruia i se aplica aceasta metoda, returnand valoarea booleana true in cazul egalitatii si valoarea booleana false in cazul inegalitatii celor doua obiecte.
In cazul claselor de biblioteca Java, metoda equals() compara ansamblul valorilor curente ale atributelor obiectului (continutul sau starea obiectului). Iata, de exemplu, implementarea metodei equals() in cazul clasei String.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//
Implementarea explicita a metodei equals() in clasa String public boolean equals(Object obj) { // se verifica existenta unui parametru (obiect) non-null //
si faptul ca parametrul e obiect al clasei String if ((obj != null) && (obj instanceof String)) { String
otherString = (String)obj; //
conversie de tip int n = this.count; if (n == otherString.count) { // se compara numarul de caractere char v1[] = this.value; char v2[] = otherString.value; int i = this.offset; int j = otherString.offset; while (n-- != 0) if (v1[i++] != v2[j++]) return
false; // se compara caracterele return true; } } return false; } |
In cazul claselor scrise de programator, in mod implicit metoda equals() compara referinta obiectului caruia i se aplica aceasta metoda cu referinta obiectului pasat ca parametru. Implementarea implicita a metodei equals() este urmatoarea:
1 2 3 4 5 6 |
// Implementarea implicita a metodei
equals(), // mostenita de la clasa Object public boolean
equals(Object obj) { return
(this == obj); // (nu compara continutul ci referintele!!!) } |
In cazul in care programatorul doreste compararea informatiilor incapsulate in obiect, (ansamblul valorilor curente ale atributelor obiectului) trebuie specificat in mod explicit un nou cod (o noua implementare) pentru metoda equals(). Acest lucru se obtine adaugand clasei din care face parte acel obiect o metoda cu declaratia:
|
public boolean equals(Object obj) { // urmeaza corpul metodei ... |
metoda care rescrie (overrides) codul metodei cu acelasi nume din clasa extinsa (in acest caz clasa Object).
Dupa adaugarea acestei metode, apelul equals() va conduce la executia noului cod, pe cand apelul super.equals()duce la executia codului din clasa extinsa (in acest caz codul din Object).
Java ofera, in pachetul java.net, mai multe clase pentru comunicatii in retele bazate pe IP (Internet Protocol).
Clasa
InetAddress incapsuleaza o adresa IP intr-un obiect
care poate intoarce informatia utila.
Aceasta informatie utila se obtine invocand metodele unui obiect al acestei
clase. De exemplu, equals() intoarce adevarat daca doua obiecte
reprezinta aceeasi adresa IP.
Clasa InetAddress nu are constructor public. De aceea, pentru a crea obiecte ale acestei clase trebuie invocata una dintre metodele de clasa getByAddress() si getByName().
Codul urmator:
1.a. 2.a. |
byte[] octetiAdresaServer = { 200, 26, 48, 100 }; InetAddress
adresaServer
= InetAddress.getByAddress(octetiAdresaServer); |
este echivalent cu:
1.b. 2.b. |
String numeMasinaServer = "java.sun.com"; InetAddress adresaServer = InetAddress.getByName(numeMasinaServer); |
si cu:
1.c. 2.c. |
String adresaIPMasinaServer = "200.26.48.100"; InetAddress adresaServer = InetAddress.getByName(adresaIPMasinaServer); |
Pentru a obtine obiectul InetAddress
care incapsuleaza adresa IP locala se
poate folosi:
|
|
O adresa IP speciala este adresa IP loopback (tot ce este trimis catre aceasta adresa IP se intoarce si devine intrare IP pentru gazda locala), cu ajutorul careia pot fi testate local programe care utilizeaza socket-uri.
Pentru a identifica adresa IP loopback sunt folosite numele "localhost" si valoarea numerica "127.0.0.1".
Pentru a obtine InetAddress
care incapsuleaza adresa IP loopback pot fi folosite apelurile echivalente:
|
|
Metoda getAddress() returneaza octetii adresei IP incapsulate, ceea ce poate fi util pentru filtrarea adreselor.
Java ofera, in pachetul java.net, mai multe clase pentru lucrul cu socket-uri flux (TCP) detalii privind socket-urile Java. Urmatoarele clase Java sunt implicate in realizarea conexiunilor TCP obisnuite: ServerSocket, Socket.
Clasa ServerSocket reprezinta socket-ul
(aflat eventual pe un server bazat pe TCP) care asteapta si accepta cereri de conexiune (eventual de la un
client bazat pe TCP).
Clasa Socket reprezinta punctul terminal al unei conexiuni TCP intre
doua masini (eventual un client si un server).
Clientul (sau, mai
general, masina conector) creeaza un punct terminal Socket in momentul in care
cererea sa de conexiune este lansata si acceptata.
Serverul (sau, mai
general, masina acceptor) creeaza un Socket in momentul in care
primeste si accepta o cerere de conexiune, si
continua sa asculte si sa astepte alte cereri pe ServerSocket.
Secventa tipica a mesajelor schimbate intre client si server este urmatoarea:
Odata conexiunea stabilita, metodele getInputStream()
si getOutputSteam()
ale clasei Socket trebuie utilizate
pentru a obtine fluxuri de octeti, de intrare respectiv iesire, pentru
comunicatia intre aplicatii.
Secventa tipica pentru crearea socket-ului unei aplicatii conector (client):
1 2 3 4 5 6 7 8 |
// Stabilirea adresei
serverului String adresaServer = "localhost"; // Stabilirea portului serverului int portServer = 2000; // Crearea socketului (implicit este realizata
conexiunea cu serverul) Socket
socketTCPClient = new Socket(adresaServer, portServer); |
Dupa utilizare, socket-ul este inchis.
Secventa tipica pentru inchiderea socket-ului:
1 2 |
// Inchiderea socketului (implicit a
fluxurilor TCP) socketTCPClient.close(); |
Program care creaza socket-uri pentru
scanarea conexiunilor TCP de pe
masina locala sau alte masini IP.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane; public class ScannerPorturiTCPSuperioare
{ public
static void main (String
args[]) { Socket socketTCP; String adresaIP = JOptionPane.showInputDialog( "Introduceti adresa IP a serverului:
"); for (int
portTCP=1024; portTCP < 65536; portTCP++)
{ try { socketTCP = new Socket(adresaIP,
portTCP); System.out.println("\nExista
un server TCP pe portul " + socketTCP.getPort() + " la
adresa " +
socketTCP.getInetAddress().getHostAddress()); socketTCP.close(); } catch
(UnknownHostException ex) {
System.err.println(ex);
break; } catch
(IOException ex) { System.err.print("."); } } } } |
In laborator: 1. Lansati in
executie BlueJ. Inchideti proiectele anterioare (Ctrl+W). Creati un proiect socket (Project->New Project
, selectati D:/, Software2006, numarul
grupei, si scrieti socket). 2. Creati o noua clasa, numita ScannerPorturiTCPSuperioare folosind codul dat mai sus. 3. Compilati
codul, apoi right-click pe clasa, selectati si executati main(). 4. Folositi
adresa localhost.
Urmariti efectul in Terminal Window.
5. Folositi apoi adresa www.yahoo.com. Folositi si alte adrese. |
Nu uitati: Daca bara de stare a executiei
este activa () verificati cu Alt+Tab daca a aparut o fereastra Java (in spatele ferestrelor
vizibile). |
Observatie: Cat timp bara de stare a executiei este activa () codul nu poate fi recompilat,
nu poate fi inchisa fereastra Terminal Window, etc. Pentru a opri executia, folositi right
click pe si selectati Reset Machine (sau folositi direct Ctrl+Shift+Tab). |
Secventa tipica pentru crearea socket-ului server al unei aplicatii acceptor (server):
1 2 3 4 5 |
// Stabilirea portului serverului int portServer
= 2000; // Crearea socketului server (care accepta
conexiunile) ServerSocket
serverTCP = new ServerSocket(portServer);
|
Secventa tipica pentru crearea socket-ului pentru tratarea conexiunii TCP cu un client:
1 2 3 4 |
//
Blocare in asteptarea cererii de conexiune - in momentul acceptarii //
cererii se creaza socketul care serveste conexiunea Socket conexiuneTCP = serverTCP.accept();
|
Un caz special este acela in care se creaza un socket server pentru o aplicatie
acceptor fara a se preciza portul pe
care asculta serverul pentru a primi cereri de conexiune si a le accepta.
In acest caz, este alocat un numar de
port aleator (unul dintre cele neocupate in acel moment). Acest lucru
se realizeaza prin pasarea valorii
0 constructorului ServerSocket().
Program pentru crearea unui socket
server cu numar de port alocat aleator.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.net.*; import java.io.*; public class InfoPortTCPAleator
{ public
static void main (String
args[]) { try { ServerSocket serverTCP = new
ServerSocket(0);
System.out.println("\nAcest
server ruleaza pe portul " +
serverTCP.getLocalPort()); serverTCP.close(); } catch (IOException ex) { System.err.println(ex); } } } |
In laborator: 1. Tot in proiectul socket creati
o clasa InfoPortTCPAleator folosind codul
dat. Compilati codul. 2. Right-click pe clasa, selectati si
executati main().Urmariti efectul in Terminal Window. 3. Repetati
operatia. Ce observati? |
Secventa tipica pentru crearea fluxurilor de octeti asociate socket-ului (detalii fluxuri IO):
1 2 3 4 5 6 7 8 9 10 11 |
// Obtinerea fluxului de intrare octeti
TCP InputStream inTCP
= socketTCPClient.getInputStream(); // Obtinerea
fluxului scanner de caractere dinspre retea Scanner scannerTCP = new Scanner(inTCP); // Obtinerea fluxului de iesire octeti TCP OutputStream outTCP = socketTCPClient.getOutputStream(); // Obtinerea fluxului de iesire spre
retea (similar consolei de iesire) PrintStream
outRetea = new PrintStream(outTCP); |
Secventa tipica pentru trimiterea de date:
1 2 3 4 5 6 |
//
Crearea unui mesaj String
mesajDeTrimis = "Continut mesaj"; // Scrierea catre retea (trimiterea mesajului) si fortarea trimiterii outRetea.println(mesajDeTrimis); outRetea.flush(); |
Secventa tipica pentru primirea de date:
1 2 3 4 5 |
// Citirea
dinspre retea (receptia unui mesaj) String
mesajPrimit = inRetea.readLine(); //
Afisarea mesajului primit
System.out.println(mesajPrimit); |
Codul unei clase care incapsuleaza tratarea conexiunilor TCP:
import java.net.*; import java.io.*; import java.util.Scanner;
public class ConexiuneRetea02 { private Socket conexiune; private Scanner scannerTCP; private PrintStream printerTCP; public ConexiuneRetea02(Socket conexiune) throws IOException { this.conexiune = conexiune; this.scannerTCP = new Scanner(conexiune.getInputStream()); this.printerTCP = new PrintStream(conexiune.getOutputStream()); } public String nextLine() { return this.scannerTCP.nextLine(); } public int nextInt() { return this.scannerTCP.nextInt(); } public void printLine(String text) { this.printerTCP.println(text); this.printerTCP.flush(); } } |
Codul unei clase care incapsuleaza
interfata (realizata grafic) cu utilizatorul:
import javax.swing.JOptionPane; // clasa de biblioteca (package) Java, externa // dar accesibila codului care urmeaza public class DialogUtilizator01 { // declaratia unei clase definite de utilizator private String prompt = "%%%"; // corpul clasei: atribut public DialogUtilizator01(String nume) { // constructor (initializator) this.prompt = nume + ": "; } public String nextLine(String text) { // metode Java (operatii) return JOptionPane.showInputDialog(this.prompt + text); } public int nextInt(String text) { return Integer.parseInt(JOptionPane.showInputDialog(this.prompt + text)); } public void printLine(String text) { JOptionPane.showMessageDialog(null, this.prompt + text); } } |
Codul unei clase Client (pentru server
cu socket TCP) care utilizeaza ConexiuneRetea02:
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class Client { private DialogUtilizator01 dialog; private ConexiuneRetea02 conexiune; private Socket socketTCP; private int portTCP; private InetAddress adresaIP;
public Client() throws IOException { dialog = new DialogUtilizator01("CLIENT"); portTCP = dialog.nextInt("Introduceti numarul de port al serverului"); adresaIP = InetAddress.getByName(dialog.nextLine("Introduceti adresa serverului")); socketTCP = new Socket(adresaIP, portTCP); // Creare socket conexiune = new ConexiuneRetea02(socketTCP); }
public static void main (String args[]) throws IOException { Client client = new Client(); String mesaj;
while(true) { mesaj = client.dialog.nextLine("Introduceti mesajul de trimis"); client.conexiune.printLine(mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire } client.socketTCP.close(); // Inchiderea socketului (si implicit a fluxurilor) client.dialog.printLine("Bye!"); } } |
Codul unei clase Server (bazat pe socket
TCP) care utilizeaza ConexiuneRetea02:
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class Server { private DialogUtilizator01 dialog; private ConexiuneRetea02 conexiune; private ServerSocket serverTCP; private Socket socketTCP; private int portTCP;
public Server() throws IOException { dialog = new DialogUtilizator01("SERVER"); portTCP = dialog.nextInt("Introduceti numarul de port al serverului"); serverTCP = new ServerSocket(portTCP); // Creare socket server socketTCP = serverTCP.accept(); // Creare socket conexiune = new ConexiuneRetea02(socketTCP); }
public static void main (String args[]) throws IOException { Server server = new Server(); String mesaj;
while(true) { mesaj = server.conexiune.nextLine(); server.dialog.printLine("S-a primit mesajul:" + mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire } server.socketTCP.close(); // Inchiderea socketului (si implicit a fluxurilor) server.dialog.printLine("Bye!"); } } |
In laborator: 1. Inchideti toate proiectele (Ctrl+W). Creati un proiect numit socket.
2. In
proiectul socket creati clasele DialogUtilizator01,
ConexiuneRetea02,
Client
si Server
folosind codurile date mai sus.
3. Compilati codurile si creati
obiecte de tip Client si Server. 4. Inspectati obiectele. 5. Inspectati campurile obiectelor
(pe cele de tip InetAddress, Socket, ServerSocket,
PrintStream si Scanner). |
In laborator: 1. La unul dintre calculatoare right-click pe clasa Server.
2. Selectati si executati main().
Folositi numarul de port 3000. 3. La un alt calculator
right-click pe clasa Client, selectati si executati main(). 4. Folositi adresa primului calculator
(pe care se executa Server) si
numarul de port 3000. 5. Urmariti
efectul in Terminal Window pe cele doua calculatoare. |
Nu uitati: Pentru a opri executia, right click pe
si Reset Machine (sau Ctrl+Shift+Tab). |
Elementele comune claselor Client si Server pot forma o superclasa numita ElementeComuneClientServer:
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ElementeComuneClientServer { protected DialogUtilizator01 dialog; protected ConexiuneRetea02 conexiune; protected Socket socketTCP; protected int portTCP;
public ElementeComuneClientServer(String tip) throws IOException { dialog = new DialogUtilizator01(tip); portTCP = dialog.nextInt("Introduceti numarul de port al serverului"); } } |
Codul unei clase ClientDerivat care mosteneste si extinde clasa
ElementeComuneClientServer si ofera acelasi serviciu ca si clasa Client:
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ClientDerivat extends ElementeComuneClientServer { private InetAddress adresaIP;
public ClientDerivat() throws IOException { super("CLIENT"); adresaIP = InetAddress.getByName(dialog.nextLine( "Introduceti adresa IP a serverului")); socketTCP = new Socket(adresaIP, portTCP); // Creare socket conexiune = new ConexiuneRetea02(socketTCP); }
public static void main (String args[]) throws IOException { ClientDerivat client = new ClientDerivat(); String mesaj;
while(true) { mesaj = client.dialog.nextLine("Introduceti mesajul de trimis"); client.conexiune.printLine(mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire } client.socketTCP.close(); // Inchiderea socketului (si implicit a fluxurilor) client.dialog.printLine("Bye!"); } } |
Codul unei clase ServerDerivat care mosteneste si extinde clasa
ElementeComuneClientServer si ofera acelasi serviciu ca si clasa Server:
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ServerDerivat extends ElementeComuneClientServer { private ServerSocket serverTCP;
public ServerDerivat() throws IOException { super("SERVER"); serverTCP = new ServerSocket(portTCP); // Creare socket server socketTCP = serverTCP.accept(); // Creare socket conexiune = new ConexiuneRetea02(socketTCP); }
public static void main (String args[]) throws IOException { ServerDerivat server = new ServerDerivat(); String mesaj;
while(true) { mesaj = server.conexiune.nextLine(); server.dialog.printLine("S-a primit mesajul:" + mesaj); if (mesaj.equals(".")) break; // Testarea conditiei de oprire } server.socketTCP.close(); // Inchiderea socketului (si implicit a fluxurilor) server.dialog.printLine("Bye!"); } } |
In laborator: 1. In
proiectul socket creati clasele ClientDerivat, ServerDerivat si ElementeComuneClientServer
folosind codurile date mai sus.
2. Compilati codurile si creati
obiecte tip ClientDerivat si ServerDerivat. 3. Inspectati obiectele. 4. Inspectati campurile obiectelor
(de tip InetAddress,
Socket, ServerSocket, PrintStream si
Scanner). |
In laborator: 1. La unul
dintre calculatoare right-click pe clasa ServerDerivat.
2. Selectati si executati main().
Folositi numarul de port 4000. 3. La un alt calculator right-click
pe clasa ClientDerivat,
selectati si executati main(). 4. Folositi adresa primului calculator
(pe care se executa ServerDerivat)
si numarul de port 4000. 5. Urmariti
efectul in Terminal Window pe cele doua calculatoare. |
Nu uitati: Daca bara de stare a executiei este activa () verificati
cu Alt+Tab daca a aparut o
fereastra Java (in spatele ferestrelor vizibile). |
Nu uitati: Pentru a opri executia, right click pe
si Reset Machine (sau Ctrl+Shift+Tab). |
Adaugarea unei clase ReleuDerivat pe post de retransmitator al mesajelor
intre ClientDerivat si ServerDerivat:
In laborator (codul complet este
parte din tema de casa!): 1. In proiectul socket creati clasa ReleuDerivat
pornind de la codurile ClientDerivat
si ServerDerivat astfel incat un client sa se poata conecta la un releu ca la un server, un releu
sa se poata conecta la un server ca un client, iar mesajele primite de un releu de la client sa fie retransmise la
server 2. La un calculator right-click pe ServerDerivat.
Executati main(). Folositi numarul de port 5000. 3. La un alt calculator
right-click pe clasa ReleuDerivat, selectati si executati main(). 4. Folositi adresa primului calculator
(pe care se executa ServerDerivat),
port 5000
si port 6000. 5. La un alt calculator
right-click pe clasa ClientDerivat, selectati si executati main(). 6. Folositi adresa celui de-al doilea
calculator (pe care se executa ReleuDerivat) si port 6000. 7. Urmariti
efectul in Terminal Window pe cele trei calculatoare. |
Crearea unor clase client si server care
ofera comunicatie bidirectionala:
In laborator (codul complet
este parte din tema de casa!): 1. In proiectul socket creati clasele ClientBidirectional
si ServerBidirectional pornind de
la codurile ClientDerivat si ServerDerivat astfel incat un utilizator al clientului sa poata discuta prin mesaje text cu un
utilizator al serverului. 2. La un calculator right-click pe ServerBidirectional.
Executati main(). Folositi portul 7000. 3. La un alt calculator
right-click pe clasa ClientBidirectional, selectati si executati main(). 4. Folositi adresa primului calculator
(pe care se executa ServerBidirectional)
si port 7000.
5. Urmariti
efectul in Terminal Window pe cele doua calculatoare. |
Adaugarea unei clase ReleuBidirectional pe post de retransmitator al
mesajelor:
In laborator: (codul complet
este parte din tema de casa!): 1. In proiectul socket creati clasa ReleuBidirectional
pornind de la codurile ClientBidirectional
si ServerBidirectional astfel
incat un client sa se poata conecta la
un releu ca la un server, un releu sa se poata conecta la un server
ca un client, mesajele primite de
un releu de la client sa fie retransmise la server si mesajele primite de un releu de la server
sa fie retransmise la client 2. La un calculator right-click pe ServerBidirectional.
Executati main(). Folositi portul 8000. 3. La un alt calculator
right-click pe clasa ReleuDerivatBidirectional, selectati si executati main(). 4. Folositi adresa primului calculator
(pe care se executa ServerBidirectional),
port 8000
si port 9000. 5. La un alt calculator
right-click pe clasa ClientBidirectional, selectati si executati main(). 6. Folositi adresa celui de-al doilea calculator
(pe care se executa ReleuDerivatBidirectional)
si port 9000.
7. Urmariti
efectul in Terminal Window pe cele trei calculatoare. |
Codurile finale ale claselor ReleuDerivat,
ClientBidirectional, ServerBidirectional,
si ReleuBidirectional (scrise pe hartie sau listinguri!)
La ultima lucrare de laborator (a 6-a, in ianuarie 2007) vor fi aduse:
- temele de mai sus,
dar si
- temele date la
primele 3 lucrari (pe care le-am vizat sau le voi viza eu).
Pe baza acestor teme (date la
lucrarile 1-4), in urma unor discutii individuale, si tinand cont de
activitatea la laborator, vor fi stabilite calificativele la laborator.