|
|
|||
|
|
22/11/2010 |
|
|
|
|
|
|
In aceasta lucrare de laborator vor fi acoperite
urmatoarele probleme:
- Lucrul
cu fire de executie programe
multifilare
- Lucrul
cu socket-uri flux (TCP) (vezi
si Lab. an V)
- Programe
de lucru cu socket-uri - clienti si servere TCP
vezi si Lab.4 An II, Lab.5 An II, Lab.6 An II)
- Anexe
Programele realizate in laboratoarele anterioare
sunt programe de calcul simple, secventiale, fiecare avand un inceput, o
secventa de executii si un sfarsit, iar in orice moment pe durata rularii lor
existand un singur punct de executie. Un
fir de executie (thread) este
similar unui program secvential, avand inceput, secventa de executii si
sfarsit, iar in orice moment al rularii lui existand un singur punct de
executie.
Totusi, un
fir nu este el insusi un program, deoarece nu poate fi executat de sine
statator. In schimb, firul este executat (rulat)
intr-un program, in paralel cu alte fire de executie. Cu alte cuvinte, programele pot executa (sau par
ca executa) mai multe operatii diferite in acelasi timp. In general, firele de executie,
partajeaza de fapt aceleasi resurse ale calculatorului (o aceiasi zona de
memorie unde sunt pastrate datele programului; utilizeaza acelasi procesor sau
aceleasi dispozitive de intrare/iesire) si in consecinta, nu pot fi executate
in paralel. Insa Java poate crea iluzia ca firele sunt executate simultan
comutand rapid controlul de la un fir la altul (fiecare fir executandu-se
pentru scurt timp inainte de a pasa controlul spre un alt fir). Posibilitatea
utilizarii mai multor fire de executie intr-un singur program este numita multithreading.
Limbajul Java permite crearea firelor de
executie prin doua metode:
1. Prin
declararea unei clase care extinde clasa
Thread. Aceasta metoda presupune
parcurgerea urmatorilor pasi:
- se creaza o clasa
derivata din clasa Thread:
class FirT extends Thread{ ... } |
- in interiorul noi clase se suprascrie
metoda public void run() mostenita
din clasa Thread:
public void run() { ... /*codul firului de executie*/ } |
- se instantiaza un obiect al noii
clase folosind operatorul new:
FirT fir = new FirT(); |
- se porneste thread-ul instantiat,
prin apelul metodei start()
mostenita din clasa Thread:
fir.start(); |
2. Prin
declararea unei clase care implementeaza
interfata Runnable (java.lang.Runnable).
(Nota1: definire interfete). Interfata Runnable contine
doar declaratia unei metode run() care
are acelasi rol cu cea din clasa Thread.
Necesitatea implementarii interfetei Runnable
apare atunci cand se doreste crearea unei clase de fire de executie care nu
extinde clasa Thread. Motivul ar
putea fi acela ca noua clasa trebuie sa extinda o alta clasa, iar in Java
mostenirea multipla nu este posibila. Aceasta metoda presupune parcurgerea
urmatorilor pasi:
- se creeaza o clasa care implementeaza
interfata Runnable:
class FirR implements Runnable { ... } |
- se implemeteaza metoda run() din
interfata Runnable:
public void run() { ... /*codul firului de executie*/ } |
- se instantiaza un obiect al noii
clase folosind operatorul new:
FirR r = new FirR(); |
- se creeaza un obiect din
clasa Thread folosind un constructor care are ca parametru un
obiect al clasei ce implementează interfata Runnable:
Thread fir = new Thread(r); |
- se porneste
thread-ul instantiat anterior, prin apelul metodei start() din clasa Thread:
fir.start(); |
Urmatorul program este folosit pentru a
ilustra lucrul cu fire de executie. Clasa FirSimplu extinde clasa Thread, iar metoda principala lanseaza metoda run() ca
nou fir de executie.
In laborator: 1. Se
deschide mediul de programare NetBeansIDE 6.1 si se sterg (click dreapta
-> Delete) toate proiectele create anterior; 2. Se
creaza un nou proiect (New Project) cu numele FireExecutie (de tipul Java / Java Class Library); 3.
Proiectul se va salva intr-ul folder de tipul: D:\LPAI\Laborator4\GrupaXYZ; 4. Se adauga un nou fisier
.java (click dreapta pe numele proiectului -> New -> Java Class...) cu
numele FirSimplu; 5. Se
implementeaza urmatoarea secventa de cod care permite lansarea unui singur
fir de executie. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class FirSimplu
extends Thread { //obiectele din clasa curenta
sunt thread-uri public FirSimplu(String str) { super(str); //
invocarea constructorului Thread(String)
// al superclasei
Thread } public
void run() { //
metoda principala a thread-ului
curent for
(int i = 0; i < 5; i++) { System.out.println(i
+ " " + getName()); // obtinerea
numelui thread-ului try
{ sleep((long)(Math.random()
* 1000)); // thread-ul
doarme 0...1 secunda }
catch (InterruptedException e) {} }
System.out.println("Gata!
" + getName()); // obtinerea
numelui thread-ului } public
static void main (String[]
args) { new FirSimplu("Unu").start(); // lansarea thread-ului
(apeleaza run()) } } |
In urma executiei programului se obtine
urmatorul rezultat:
Metoda run() este cea care contine programul propriu-zis care trebuie executat
de un fir de executie. Totusi,
aceasta metoda nu este invocata explicit. Ea este invocata de masina virtuala
Java, atunci cand firul respectiv este pus in mod efectiv in executie. Prin
apelarea metodei start(), firul va fi pregatit de
executie, dar nu neaparat va si rula imediat. El devine concurent cu
alte fire deja existente (in primul rand cu cel care l-a creat), si va fi pus
in executie in mod efectiv (i se va acorda acces la procesor) atunci cand ii
vine randul, conform cu strategia de alocare a resurselor adoptata.
Un fir in curs de executie poate fi oprit
pentru o perioada de timp invocand metoda sleep(long millis).
Argumentul millis reprezinta timpul
cat firul de executie va fi adormit (se va opri din executie), exprimat in
milisecunde.
Clasa DemoDouaFire lanseaza doua fire de executie
de tip FirSimplu
executate concurent.
1 2 3 4 5 6 |
public class DemoDouaFire
{ public
static void main (String[]
args) { new FirSimplu("Unu").start(); // lansarea
primului thread new FirSimplu("Doi").start(); // lansarea
celui de-al doilea thread } } |
Firele au evolutii diferite, in functie de durata intarzierii introdusa in
linia de cod:
sleep((long)(Math.random() * 1000));
a programului FirSimplu.
Rezultatele a doua executii
succesive:
In laborator: 1. Se
vor modifica cele doua clase definite anterior ( / crea altele noi) astfel
incat sa se foloseasca cea de-a doua metoda de creare a firelor de executie
(prin implementarea interfetelor Runnable). |
Hint! Deoarece clasa FirSimplu nu
mai mosteneste clasa Thread, metodele getName() si sleep() nu mai pot fi accesate direct. Apelarea acestora se va face
astfel: Thread.currentThread().getName() si Thread.currentThread().sleep(...); |
Pentru
realizarea unor programe care sa comunice in retelele bazate pe IP (Internet
Protocol), programul Java pune la dispozitie o serie de clase utile,
disponibile in pachetul java.net.
Comunicare in Internet intre doua terminale, respectind modelul client-server
presupune stabilirea unei conexiuni ce se bazeaza pe adresa IP a serverului si
numarul portului pe care este deschisa aplicatia (valori intre 0 si 65535).
Combinația, adresa IP si numarul portului este folosită pentru crearea unui
termen abstract, numit socket (canal de comunicatie). Un socket permite crearea
de fluxuri de intrare/iesire utile pentru schimbul de date intre client si
server. La stabilirea unei conexiuni, atat clientul cat si serverul vor avea
asociate cate un socket, comunicarea efectiva realizandu-se intre socketuri.
Principalele functii indeplinite de socketuri
sunt:
-
conectarea la un socket corespondent;
-
acceptarea conexiunilor;
-
trimiterea de date
-
recepționarea datelor
-
inchiderea conexiunii cu socket-ul corespondent;
Java ofera, in pachetul java.net, mai multe clase pentru lucrul cu socket-uri
flux (TCP). Urmatoarele clase Java
sunt implicate in realizarea conexiunilor TCP obisnuite: ServerSocket si Socket.
Clasa ServerSocket reprezinta socket-ul aflat pe un server (bazat
pe TCP) care asteapta si accepta cereri de conexiune provenite din partea unui
client (bazat eventual tot 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. Acesta continua apoi sa asculte si sa astepte alte cereri pe ServerSocket.
Dintre
metodele clasei ServerSocket, cele mai importante sint accept() si close().
Metoda accept() este folosita pentru
crearea unui socket si atasarea acestuia la un port al serverului, iar metoda close() este utilizata pentru a inchide
o conexiune care s-a terminat. ServerSocket va returna clientului prin metoda
accept(), socket-ul deschis pe server pentru realizarea comunicatiei. Este
stabilita astfel o conexiune Socket la Socket.
Secventa tipica a mesajelor schimbate
intre client si server este urmatoarea:
Odata conexiunea stabilita, metodele
getInputStream() si getOutputStream() ale clasei Socket pot fi utilizate (pentru fiecare
socket in parte) pentru a obtine fluxuri de octeti, de intrare respectiv
iesire, pentru comunicatia intre aplicatii.
Java ofera, in pachetul java.net, clasa InetAddress care poate furniza informatii despre adresa (simbolică și numerică) unui calculator gazda. Clasa InetAddress nu are constructori publici. De aceea, pentru a crea obiecte ale acestei clase trebuie invocata una dintre metodele de clasa getByAddress() sau getByName().
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 urmatoarele apelurile:
InetAddress.getByName(null) InetAddress.getByName("localhost") InetAddress.getByName("127.0.0.1") |
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(); |
Secventa tipica pentru crearea ServerSocket-ului pentru
o aplicatie 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(); |
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 scanTCP =
new Scanner(inTCP); // Obtinerea fluxului de
iesire octeti TCP OutputStream outTCP
= socketTCPClient.getOutputStream(); // Obtinerea fluxului de
iesire spre retea (similar consolei de iesire) PrintStream printTCP = 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 printTCP.println(mesajDeTrimis); printTCP.flush(); |
Secventa tipica pentru primirea de date:
1 2 3 4 5 |
// Citirea dinspre retea (receptia unui mesaj) String mesajPrimit = scanTCP.nextLine();
// Afisarea mesajului primit System.out.println(mesajPrimit); |
Clasa urmatoare ofera un
"serviciu" accesibil la distanta prin intermediul unui server TCP
unifilar (care poate trata un singur client o data):
In laborator: 1. Se
creaza un nou proiect (New Project) cu numele ClientServerTCP (de tipul Java / Java
Class Library); 2.
Proiectul se va salva intr-ul folder de tipul: D:\LPAI\Laborator4\GrupaXYZ; 3. Se adauga un nou fisier
.java (click dreapta pe numele proiectului -> New -> Java Class...) cu
numele Orar; 4. Se
implementeaza urmatoarea secventa de cod. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class
Orar { private String[] orar; // public Orar() { orar =
new String[7]; // alocarea dinamica a
spatiului pentru tablou // popularea tabloului cu valori orar[0] = "Luni nu sunt ore de
LPAI."; orar[1] = "Marti sunt
laboratoare de LPAI."; orar[2] = "Miercuri nu sunt ore
de LPAI."; orar[3] = "Joi sunt proiecte de LPAI."; orar[4] = "Vineri este curs de LPAI."; orar[5] =
"Sambata nu sunt ore de LPAI."; orar[6] =
"Duminica nu sunt ore de LPAI."; } public String
getOrar(int zi) { // metoda accesor -
getter return orar[zi]; // returneaza referinta la tablou } public void
setOrar(int zi, String text) { //
metoda accesor - setter orar[zi]
= text; // inlocuieste un element } } |
Clasa server care urmeaza permite accesul
la "serviciile" oferit de clasa de mai sus, prin crearea unui obiect
din aceasta clasa si apelul metodelor accesor:
In laborator: 1. In proiectul ClientServerTCP se adauga un nou
fisier .java cu numele ServerUnifilarTCP1. 2. Se
implementeaza urmatoarea secventa de cod. |
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
import java.net.*; import java.io.*; import
java.util.Scanner; import
javax.swing.JOptionPane; public class
ServerUnifilarTCP1 { private
Scanner scanTCP; private
PrintStream printTCP; private
ServerSocket serverTCP; private
Socket socketTCP; private
int portTCP; private Orar orar = new Orar(); public ServerUnifilarTCP1(Socket
conexiuneTCP) throws IOException {
this.socketTCP = conexiuneTCP;
// Obtinere socket this.scanTCP = new
Scanner(socketTCP.getInputStream()); this.printTCP = new PrintStream(socketTCP.getOutputStream()); } public void run() {
String mesaj; int
zi; try
{ while(true) { if (scanTCP.hasNextLine()) { mesaj =
scanTCP.nextLine(); if (mesaj.equals("getOrar"))
{ try { zi =
Integer.parseInt(scanTCP.nextLine());
JOptionPane.showMessageDialog(null,
"Server: am primit " + mesaj + " si " + zi); String rezultat = orar.getOrar(zi);
printTCP.println(rezultat); printTCP.flush(); } catch
(NumberFormatException ex) { printTCP.println("Stop"); printTCP.flush(); break; }
}
/* else if
(mesaj.equals("setOrar")) { } */
else {
printTCP.println("Stop");
printTCP.flush(); break;
}
}
} socketTCP.close(); // Inchiderea socketului si a fluxurilor
JOptionPane.showMessageDialog(null, "Server: Bye!"); }
catch (IOException ex) {
ex.printStackTrace(); } } public
static void main(String[] args) throws IOException { int
portTCP = Integer.parseInt(JOptionPane.showInputDialog( "Server:
introduceti numarul de port al serverului")); //
Creare socket server ServerSocket
serverTCP = new ServerSocket(portTCP); Socket conexiune =
serverTCP.accept(); // Obtinere socket ServerUnifilarTCP1 server = new
ServerUnifilarTCP1(conexiune); server.run(); } } |
Relatia intre clasele de mai sus este
ilustrata in diagrama UML urmatoare:
Clasa client care urmeaza (ClientTCP1) permite
utilizatorilor accesul la distanta la "serviciul" aflat pe aceeasi
masina cu serverul TCP anterior. Utilizatorul poate accesa (getOrar), prin
intermediul acestui client, informatiile stocate in obiectul din clasa Orar de pe server.
In laborator: 1. In proiectul ClientServerTCP se adauga un nou
fisier .java cu numele ClientTCP1. 2. Se
implementeaza urmatoarea secventa de cod. |
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
import java.awt.*; import
java.awt.event.*; import javax.swing.*; import java.net.*; import java.io.*; import java.util.*; public class
ClientTCP1 { private
Scanner scanTCP; private
PrintStream printTCP; private
Socket socketTCP; private
int portTCP; private
InetAddress adresaIP; private
JFrame frame; public ClientTCP1() throws IOException
{ this.portTCP =
Integer.parseInt(JOptionPane.showInputDialog( "Client: introduceti
numarul de port al serverului"));
this.adresaIP = InetAddress.getByName(JOptionPane.showInputDialog( "Client: introduceti adresa serverului")); this.socketTCP = new Socket(adresaIP,
portTCP); // Creare socket
this.scanTCP = new Scanner(socketTCP.getInputStream());
this.printTCP = new PrintStream(socketTCP.getOutputStream()); frame = new JFrame("Client
TCP");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container containerCurent =
frame.getContentPane();
containerCurent.setLayout(new BorderLayout()); JPanel pane = new JPanel(new
GridLayout(0, 1)); final JLabel eticheta = new
JLabel("Orarul zilei de:");
pane.add(eticheta);
final int numButtons = 8; final JRadioButton[] radioButtons =
new JRadioButton[numButtons]; final ButtonGroup group = new ButtonGroup(); radioButtons[0] = new
JRadioButton("Luni");
radioButtons[0].setActionCommand("0");
radioButtons[1] = new JRadioButton("Marti");
radioButtons[1].setActionCommand("1");
radioButtons[2] = new JRadioButton("Miercuri");
radioButtons[2].setActionCommand("2");
radioButtons[3] = new JRadioButton("Joi");
radioButtons[3].setActionCommand("3");
radioButtons[4] = new JRadioButton("Vineri"); radioButtons[4].setActionCommand("4");
radioButtons[5] = new JRadioButton("Sambata");
radioButtons[5].setActionCommand("5");
radioButtons[6] = new JRadioButton("Duminica");
radioButtons[6].setActionCommand("6"); radioButtons[7]
= new JRadioButton("Stop");
radioButtons[7].setActionCommand("Stop");
radioButtons[0].setSelected(true); for
(int i = 0; i < numButtons; i++) {
group.add(radioButtons[i]); pane.add(radioButtons[i]); }
containerCurent.add(pane, BorderLayout.WEST); JButton sendButton = new JButton("Trimite"); sendButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent
e) { String service =
"getOrar"; printTCP.println(service);
printTCP.flush(); String command =
group.getSelection().getActionCommand(); printTCP.println(command);
printTCP.flush();
} });
containerCurent.add(sendButton, BorderLayout.NORTH); final JTextArea outGrafic = new
JTextArea(8,40); //Zona non-editabila
JScrollPane scrollPane = new JScrollPane(outGrafic,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
outGrafic.setEditable(false);
containerCurent.add(outGrafic, BorderLayout.CENTER); frame.pack();
frame.setVisible(true);
String mesaj; while(true) { if (scanTCP.hasNextLine()) { mesaj = scanTCP.nextLine();
outGrafic.setText(outGrafic.getText() + mesaj + "\n"); if (mesaj.equals("Stop"))
System.exit(0); // Conditie oprire } } } public
static void main(String[]
args) throws IOException {
ClientTCP1 client = new ClientTCP1(); } } |
Urmatoarea diagrama UML reflecta codul de
mai sus:
In laborator: 1. Se selecteaza Run File pe nodul clasei cu numele ServerUnifilarTCP1. 2. Se
introduce valoarea 3000 pentru
portul pe care asculta serverul TCP. |
In laborator: 1. Se selecteaza Run File pe nodul clasei cu numele ClientTCP1. 2. Se
introduce valoarea 3000 pentru
portul serverului si adresa IP a
calculatorului pe care a fost lansat serverul, sau se apasa Cancel (generandu-se
astfel adresa loopback localhost
127.0.0.1). |
In laborator: 1. Se utilizeaza interfata
clientului. 2.
Pentru oprire se selecteaza Stop
si se apasa Trimite. |
Clasa client care urmeaza (ClientTCP2) permite de asemenea accesul la distanta
la "serviciul" aflat pe aceeasi masina cu serverul TCP anterior. Utilizatorul poate modifica (setOrar), prin intermediul acestui client,
informatiile stocate in obiectul din clasa Orar de pe server.
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 00 01 02 03 04 05 06 07 08 09 |
import java.awt.*; import
java.awt.event.*; import javax.swing.*; import java.net.*; import java.io.*; import java.util.*; public class
ClientTCP2 { private
Scanner scanTCP; private
PrintStream printTCP; private
Socket socketTCP; private
int portTCP; private
InetAddress adresaIP; private
JFrame frame; public ClientTCP2() throws IOException
{
this.portTCP = Integer.parseInt(JOptionPane.showInputDialog( "Client:
introduceti numarul de port al serverului")); this.adresaIP =
InetAddress.getByName(JOptionPane.showInputDialog( "Client: introduceti
adresa serverului")); this.socketTCP = new Socket(adresaIP,
portTCP); // Creare socket this.scanTCP = new
Scanner(socketTCP.getInputStream()); this.printTCP = new PrintStream(socketTCP.getOutputStream());
JFrame frame = new JFrame("Client TCP");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container containerCurent = frame.getContentPane();
containerCurent.setLayout(new BorderLayout());
JPanel pane = new JPanel(new GridLayout(0, 1)); final JLabel eticheta = new JLabel("Modificarea orarului zilei
de:"); pane.add(eticheta);
final int numButtons = 8;
final JRadioButton[] radioButtons = new JRadioButton[numButtons];
final ButtonGroup group = new ButtonGroup();
radioButtons[0] = new JRadioButton("Luni");
radioButtons[0].setActionCommand("0");
radioButtons[1] = new JRadioButton("Marti");
radioButtons[1].setActionCommand("1");
radioButtons[2] = new JRadioButton("Miercuri");
radioButtons[2].setActionCommand("2");
radioButtons[3] = new JRadioButton("Joi");
radioButtons[3].setActionCommand("3");
radioButtons[4] = new JRadioButton("Vineri");
radioButtons[4].setActionCommand("4");
radioButtons[5] = new JRadioButton("Sambata");
radioButtons[5].setActionCommand("5");
radioButtons[6] = new JRadioButton("Duminica");
radioButtons[6].setActionCommand("6");
radioButtons[7] = new JRadioButton("Stop");
radioButtons[7].setActionCommand("Stop");
radioButtons[0].setSelected(true); for
(int i = 0; i < numButtons; i++) {
group.add(radioButtons[i]);
pane.add(radioButtons[i]); }
containerCurent.add(pane, BorderLayout.WEST);
final JTextField inTextGrafic = new JTextField(40); //Camp editabil
intrare containerCurent.add(inTextGrafic,
BorderLayout.SOUTH);
JButton sendButton = new JButton("Trimite"); sendButton.addActionListener(new
ActionListener() { public void
actionPerformed(ActionEvent e) { String service =
"setOrar"; printTCP.println(service);
printTCP.flush(); String command =
group.getSelection().getActionCommand(); printTCP.println(command); printTCP.flush(); printTCP.println(inTextGrafic.getText());
printTCP.flush();
inTextGrafic.setText("");
} });
containerCurent.add(sendButton, BorderLayout.NORTH);
final JTextArea outGrafic = new JTextArea(8, 40); // Zona
non-editabila
JScrollPane scrollPane = new JScrollPane(outGrafic,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
outGrafic.setEditable(false);
containerCurent.add(outGrafic, BorderLayout.CENTER);
inTextGrafic.requestFocus(); // Cerere focus pe intrarea de text
frame.pack();
frame.setVisible(true);
String mesaj; while(true) { if (scanTCP.hasNextLine()) { mesaj = scanTCP.nextLine();
outGrafic.setText(outGrafic.getText() + mesaj + "\n"); if
(mesaj.equals("Stop")) System.exit(0); // Conditie oprire } } } public
static void main(String[] args) throws IOException {
ClientTCP2 client = new ClientTCP2(); } } |
In laborator: 1. Se selecteaza Run File pe nodul clasei cu numele ServerUnifilarTCP1. 2. Se
introduce valoarea 4000 pentru
portul pe care asculta serverul TCP. 3. . Se selecteaza Run File pe nodul clasei cu numele ClientTCP2. 4. Se introduce valoarea 4000 pentru portul serverului si se
introduce adresa IP a calculatorului pe care a fost lansat serverul, sau se apasa Cancel (generandu-se astfel adresa localhost). 5. Se
utilizeaza interfata clientului pentru modificarea orarului. |
Atentie! Se poate observa ca de fiecare data cand
se incearca modificarea unei zile din orar si se apasa butonul Trimite, serverul ne afiseaza
mesajul: Server: Bye! si se inchide. |
In laborator: 1. Sa se modifice/completeze
codul clasei ServerUnifilarTCP1 pentru a putea oferi
si serviciul de modificare a orarului (setOrar); 2. Dupa ce serverul face
modificarea efectiva in orar, sa trimita clientului un mesaj de confirmare,
pe baza caruia clientul sa afiseze in obiectul JTextArea outGrafic
modificarea facuta; 2. Se reiau pasii necesari
executiei
ServerUnifilarTCP1 si ClientTCP2; 3. Se
utilizeaza interfata clientului. Pentru oprire se selecteaza Stop si se apasa Trimite. |
Clasa server care urmeaza permite accesul
mai multor clienti in acelasi timp la "serviciile" oferite de clasa Orar (prin implementarea firelor de executie).
Clientii pot fi din ambele categorii anterioare, permitand astfel modificarea
continutului orarului in timp ce acesta este vizualizat.
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
import java.net.*; import java.io.*; import
java.util.Scanner; import
javax.swing.JOptionPane; public class
ServerMultifilarTCP1 extends Thread { private
Scanner scanTCP; private
PrintStream printTCP; private
Socket socketTCP; private static
Orar orar = new Orar(); public ServerMultifilarTCP1(Socket
conexiuneTCP) throws IOException {
this.socketTCP = conexiuneTCP;
// Obtinere socket this.scanTCP = new
Scanner(socketTCP.getInputStream()); this.printTCP = new
PrintStream(socketTCP.getOutputStream()); } public void run() { String
mesaj; int
zi; try {
while(true) { if (scanTCP.hasNextLine()) { mesaj = scanTCP.nextLine(); if (mesaj.equals("getOrar"))
{
try { zi =
Integer.parseInt(scanTCP.nextLine());
JOptionPane.showMessageDialog(null,"Server:am primit"
+ mesaj + " si " + zi); String rezultat =
orar.getOrar(zi);
printTCP.println(rezultat);
printTCP.flush();
} catch
(NumberFormatException ex) {
printTCP.println("Stop");
printTCP.flush(); break; }
} /* else if
(mesaj.equals("setOrar")) { } */ else {
printTCP.println("Stop");
printTCP.flush();
break;
}
} }
socketTCP.close(); //
Inchiderea socketului si a fluxurilor
JOptionPane.showMessageDialog(null, "Server: Bye!"); } catch
(IOException ex) {
ex.printStackTrace(); } } public static void main(String[] args)
throws IOException { int
portTCP = Integer.parseInt(JOptionPane.showInputDialog( "Server:
introduceti numarul de port al serverului"));
ServerSocket serverTCP=new ServerSocket(portTCP);//Creare socket
server while (true) { Socket conexiune =
serverTCP.accept(); ServerMultifilarTCP1 server = new
ServerMultifilarTCP1(conexiune); server.start(); } } } |
In laborator: 1. Se selecteaza Run File pe nodul clasei cu numele ServerMultifilarTCP1; 2. Se
introduce valoarea 5000 pentru
portul pe care asculta serverul TCP; 3. Se
selecteaza Run File pe nodul
clasei cu numele ClientTCP1; 4. Se
introduce valoarea 5000 pentru
portul serverului si se introduce adresa IP a calculatorului pe care a fost
lansat serverul, sau se apasa Cancel (generandu-se astfel adresa
localhost); 5. Se
selecteaza Run File pe nodul
clasei cu numele ClientTCP2; 6. Se introduce valoarea 5000 pentru portul serverului si se
introduce adresa IP a calculatorului pe care a fost lansat serverul, sau se
apasa Cancel (generandu-se astfel adresa localhost). |
Atentie! Se poate observa ca de fiecare data cand
se incearca modificarea unei zile din orar si se apasa butonul Trimite, serverul ne afiseaza
mesajul: Server: Bye! si se inchide. |
In laborator: 1. Sa se modifice/completeze
codul clasei ServerMultifilarTCP1 pentru a putea oferi
si serviciul de modificare a orarului (setOrar); 2. Dupa ce serverul face
modificarea efectiva in orar, sa trimita clientului un mesaj de confirmare,
pe baza caruia clientul sa afiseze in obiectul JTextArea outGrafic
modificarea facuta; 3. Se reiau pasii necesari
executiei
ServerMultifilarTCP1, ClientTCP1 si ClientTCP2; |
Urmatoarea diagrama UML reflecta codul de
mai sus:
Asa trebuie sa arate interfata ClientTCP1 dupa modificarile cerute
si utilizarea unui client de tip ClientTCP1 si a unuia de tip ClientTCP2 (prin intermediul caruia orarul zilei de sambata
a fost modificat in "Recuperare ore pierdute"):
Tema 1. Fiecare grup
de 2 studenti (cei 2 studenti care lucreaza la acelasi calculator in cadul
laboratorului) isi va alege o alta disciplina pentru care sa realizeze orarul
(care va trebui sa corespunda celui real din acest semestru). Codul actual al
clasei Orar va fi modificat pentru a permite aflarea
orarului detaliat (incluzand orele de desfasurare) la respectiva disciplina, si
personalizat pentru grupa si subgrupa din care fac parte studentii care il
realizeaza (similar temei de la laboratorul anterior). 2pct
Tema 2. Adaugarea
unui buton care sa permita oprirea serverului multifilar de catre clientii care
permit modificarea orarului (de tip 2). 2pct
Tema 3. Adaptarea
aplicatiilor de la clienti pentru a deveni appleturi. 3pct
Tema 4. Se va inlocui
butonul Trimite cu doua butoane
(441F si
442F) care vor permite afisarea alternativa a orarului pentru cele doua
subgrupe. 4pct
Tema 5. Se va crea un
al 3-lea tip de client care sa permita atat vizualizarea cat si modificarea
datelor de pe server. Metoda de implementare este la alegere (Ex: 1. prin
utilizarea unui obiect de tip JCheckBox; 2. prin utilizarea a doua butoane; 3. prin
utilizarea unui alt grup de 2 obiecte JRadioButton; 4. alta
metoda); 5pct
Tema 6. Crearea altui
serviciu, pe formatul celui oferit de clasa Orar, si adaptarea serverului si clientilor la noul serviciu (se vor modifica
de asemenea si componentele grafice in interfata).4pct
Temele vor fi predate la lucrarea urmatoare, cate
un exemplar pentru fiecare grup de 2 studenti, pe hartie (avand numele celor doi studenti scrise pe prima pagina
sus) sub forma de listing. Se pot
implementa la alegere un numar de teme din cele prezentate mai sus. Se pot realiza toate temele, dar punctajul
maxim este de 12 puncte (10+bonus).
1.1. Java
Tutorials: Learning Swing with the
NetBeans IDE
(http://java.sun.com/docs/books/tutorial/uiswing/learn/index.html)
1.2. Java
Tutorials: How
to Use Buttons, Check Boxes, and Radio Buttons
(http://java.sun.com/docs/books/tutorial/uiswing/components/button.html)
1.3. Java
Tutorials: How
to Use Combo Boxes
(http://java.sun.com/docs/books/tutorial/uiswing/components/combobox.html)
1.4. Java
Tutorials: How
to Use Lists
(http://java.sun.com/docs/books/tutorial/uiswing/components/list.html)
Nota1: Definire
interfete Java: O interfata Java defineste un set de metode pentru care nu se
specifica insa nici o implementare (doar semnatura). O clasa care implementeaza
o interfata trebuie obligatoriu sa specifice implementari pentru toate metodele
interfetei, supunându-se asadar unui anumit comportament. O interfata poate fi vazuta ca o colectie de
metode, fara implementare, si declaratii de constante. Interfețele
sunt elemente fundamentale în sistemele OO. Obiectele sunt cunoscute doar prin
intermediul interfețelor lor. O interfața nu dă nici un detaliu relativ la
implementarea unui obiect, iar obiecte distincte pot implementa diferit o
aceeași cerere.
O interfață Java este declarată prin cuvântul cheie interface:
[public] interface NumeInterfata
[extends
SuperInterfata1 [,extends SuperInterfata2...]] { //corpul
interfetei:constane si metode abstracte } |