In aceasta lucrare de laborator vor fi acoperite urmatoarele probleme:
- Utilizarea firelor de
executie (clasa Threads) – Introducere in fire de executie – link extern
- Aplicatii client-server cu
interfata grafica Swing bazate pe socket-uri TCP
- Precizari
privind mini-proiectul pentru examenul final
Pentru a crea un nou fir de executie (detalii
privind firele de executie - threads
- in Java) exista doua modalitati.
1. Se poate declara o
clasa ca subclasa a clasei Thread
, subclasa care trebuie sa rescrie codul (override)
metodei run
()
a clasei Thread
(care nu contine nici un cod), noul fir de executie fiind creat prin
alocarea si lansarea unei instante a subclasei.
Formatul pentru crearea unei subclase care extinde clasa Thread
si ii reimplementeaza metoda run()
este urmatorul:
class FirT extends Thread { public void run() { // codul firului de executie } } |
Formatul pentru crearea unei instante a subclasei este urmatorul:
FirT fir = new FirT(); |
2. Se poate declara o clasa care implementeaza interfata Runnable
, interfata care contine doar declaratia unei
metode run
()
(declaratie similara celei din clasa Thread
, clasa Thread
implementand interfata Runnable
), noul fir fiind obtinut prin crearea unei instante a noii clase, pasata constructorului la crearea unei instante a clasei Thread
, si lansarea noii instante a clasei
Thread
.
Formatul pentru crearea unei clase care implementeaza interfata Runnable
si ii implementeaza metoda run()
este urmatorul:
class FirR implements Runnable { public void run() { // codul firului de executie } } |
Formatul pentru crearea unei instante a noii clase si apoi a unei instante
a clasei Thread
este urmatorul:
FirR r = new FirR(); Thread fir = new Thread(r); |
In ambele cazuri formatul pentru lansarea noului fir de
executie, este urmatorul:
fir.start(); |
Variante compacte pentru crearea si lansarea noilor fire de executie:
new FirT().start(); // nu exista variabila de tip FirT // care sa refere explicit firul |
FirR r = new FirR(); new Thread(r).start(); // nu exista variabila de tip Thread // care sa refere explicit firul |
Thread fir = new Thread(new FirR()); // nu exista variabila de tip FirR fir.start(); // care sa refere explicit firul |
new Thread(new FirR()).start(); // nu exista variabila de tip Thread // si nici variabila de tip FirR // care sa refere explicit firul |
Urmatorul program va fi folosit pentru a
exeplifica lucrul cu fire de executie.
Clasa FirSimplu
extinde clasa Thread, iar metoda
principala lanseaza metoda run() ca nou fir de executie.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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()) } } |
Clasa DemoTreiFire lanseaza trei fire de
executie de tip FirSimplu
executate concurent.
1 2 3 4 5 6 7 |
public
class DemoTreiFire { public
static void main (String[]
args) { new FirSimplu("Unu").start(); // “lansarea”
primului thread new FirSimplu("Doi").start(); // “lansarea”
celui de-al doilea thread new FirSimplu("Trei").start(); // “lansarea”
celui de-al treilea thread } } |
Firele au evolutii diferite, in functie de durata intarzierii introdusa in FirSimplu de linia:
sleep( (long) (Math.random() * 1000) );
In laborator: 1. Inchideti proiectele anterioare
(Ctrl+W). Creati un nou proiect fire 2. Creati o noua clasa, numita
FirSimplu,
folosind codul dat mai sus. 3. Creati un obiect tip FirSimplu
(cu nume "Test"), inspectati-i campurile (atributele) si metodele. 4. Tot in proiectul fire
creati clasa DemoTreiFire
folosind codul de mai sus. Compilati clasele. 5. Right-click pe clasa,
selectati si executati main().
Urmariti efectul in Terminal Window.
|
Superclasa ElementeComuneClientServer contine elemente comune clientilor si serverelor si este mostenita si
extinsa de clienti si servere:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ElementeComuneClientServer { protected ConexiuneRetea conexiune; protected Socket socketTCP; protected int portTCP;
public ElementeComuneClientServer(String tip) throws IOException { portTCP = Integer.parseInt(JOptionPane.showInputDialog(tip + ": introduceti numarul de port al serverului")); } } |
Clasa utilitara ConexiuneRetea incapsuleaza
tratarea conexiunilor TCP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import java.net.*; import java.io.*; import java.util.Scanner;
public class ConexiuneRetea { private Socket conexiune; private Scanner scannerTCP; private PrintStream printerTCP; public ConexiuneRetea(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(); }
} |
Clasa ClientBidirectionalSwing mosteneste
si extinde clasa ElementeComuneClientServer:
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 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane; import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class ClientBidirectionalSwing
extends ElementeComuneClientServer
implements Runnable { private InetAddress adresaIP; private JFrame frame; private JTextField inTextGrafic; // Intrare
- linie text grafica (JtextField) private JTextArea outTextGrafic; // Iesire - zona text grafica (JtextArea) private JScrollBar vertical; private String sirCitit; public ClientBidirectionalSwing()
throws IOException { super("Client"); adresaIP = InetAddress.getByName(JOptionPane.showInputDialog( "Client:
introduceti adresa serverului")); socketTCP = new Socket(adresaIP,
portTCP); // Creare socket conexiune
= new ConexiuneRetea(socketTCP); // Crearea
obiectului cadru (frame), cu titlu specificat JFrame frame = new JFrame("Client bidirectional Swing"); //
Stabilire titlu Container containerCurent = frame.getContentPane(); containerCurent.setLayout(new BorderLayout()); outTextGrafic = new JTextArea(5,
40); // Zona text non-editabila de
iesire JScrollPane scrollPane = new JScrollPane(outTextGrafic,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); vertical = scrollPane.getVerticalScrollBar(); containerCurent.add("Center",
scrollPane); outTextGrafic.setEditable(false); outTextGrafic.append("Pentru oprire introduceti '.'
si <Enter>\n\n"); inTextGrafic = new JTextField(40); // Camp de text editabil de intrare containerCurent.add("South",
inTextGrafic); inTextGrafic.requestFocus();
// Cerere focus pe intrarea text // Inregistrare
"ascultator" de "evenimente actionare" la "obiectul
sursa" inTextGrafic.addActionListener(new AscultatorInText()); // Iesire din program la inchiderea
ferestrei frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); // Impachetarea (compactarea)
componentelor in container frame.setVisible(true); // Fereastra devine vizibila } // Clasa interna
"ascultator" de "evenimente actionare" // implementeaza interfata
ActionListener class AscultatorInText implements ActionListener { // Tratarea actionarii
intrarii de text (introducerii unui "Enter") public void actionPerformed(ActionEvent
ev) { sirCitit = inTextGrafic.getText();
// Citirea unei linii din intrarea text inTextGrafic.setText(""); // Golirea intrarii text conexiune.printLine(sirCitit); outTextGrafic.append("S-a introdus: "+sirCitit+"\n"); // Scriere linie // actualizeaza pozitia barei de
defilare, varianta imbunatatita a // vertical.setValue(vertical.getMaximum()
- vertical.getVisibleAmount()); SwingUtilities.invokeLater(new
Runnable() { public void run() {
vertical.setValue(vertical.getMaximum()); } }); if (sirCitit.equals(new String("."))) System.exit(0); // Conditie oprire }
} public void run () { String mesaj; while (true) { mesaj = conexiune.nextLine(); outTextGrafic.append("S-a primit: " +
mesaj + "\n"); // actualizeaza pozitia barei
de defilare, varianta imbunatatita a //
vertical.setValue(vertical.getMaximum() - vertical.getVisibleAmount()); SwingUtilities.invokeLater(new Runnable() { public void run() {
vertical.setValue(vertical.getMaximum()); } }); if (mesaj.equals("."))
break; // Testarea conditiei de
oprire } try {
socketTCP.close();
// Inchiderea socketului si a fluxurilor } catch (IOException ex) {} JOptionPane.showMessageDialog(null,
"Client: Bye!"); } public static void main (String args[])
throws IOException { ClientBidirectionalSwing
client = new ClientBidirectionalSwing(); new Thread(client).start(); } } |
Clasa ServerBidirectionalSwing mosteneste
si extinde clasa ElementeComuneClientServer:
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 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ServerBidirectionalSwing
extends ElementeComuneClientServer
implements Runnable { private ServerSocket serverTCP; private JFrame frame; private JTextField inTextGrafic; // Intrare -
linie text grafica (JtextField) private JTextArea outTextGrafic; // Iesire - zona text grafica (JtextArea) private JScrollBar vertical; private String sirCitit; public ServerBidirectionalSwing()
throws IOException { super("Server"); serverTCP = new ServerSocket(portTCP); // Creare socket server socketTCP = serverTCP.accept(); // Creare socket conexiune
= new ConexiuneRetea(socketTCP); // Crearea obiectului cadru
(frame), cu titlu specificat JFrame frame = new JFrame("Server bidirectional Swing"); //
Stabilire titlu Container containerCurent = frame.getContentPane(); containerCurent.setLayout(new BorderLayout()); outTextGrafic = new JTextArea(5,
40); // Zona text non-editabila de
iesire JScrollPane scrollPane =
new JScrollPane(outTextGrafic,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); vertical = scrollPane.getVerticalScrollBar(); containerCurent.add("Center",
scrollPane); outTextGrafic.setEditable(false); outTextGrafic.append("Pentru oprire introduceti '.'
si <Enter>\n\n"); inTextGrafic = new JTextField(40); // Camp de text editabil de intrare containerCurent.add("South",
inTextGrafic); inTextGrafic.requestFocus();
// Cerere focus pe intrarea text // Inregistrare "ascultator"
de "evenimente actionare" la "obiectul sursa" inTextGrafic.addActionListener(new AscultatorInText()); // Iesire din program la inchiderea
ferestrei frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); // Impachetarea (compactarea)
componentelor in container frame.setVisible(true); // Fereastra devine vizibila } // Clasa interna
"ascultator" de "evenimente actionare" // implementeaza interfata
ActionListener class AscultatorInText implements ActionListener { // Tratarea actionarii
intrarii de text (introducerii unui "Enter") public void actionPerformed(ActionEvent
ev) { sirCitit = inTextGrafic.getText();
// Citirea unei linii din intrarea text inTextGrafic.setText(""); // Golirea intrarii text conexiune.printLine(sirCitit); outTextGrafic.append("S-a introdus: "+sirCitit+"\n"); // Scriere linie // actualizeaza pozitia barei de
defilare, varianta imbunatatita a //
vertical.setValue(vertical.getMaximum() - vertical.getVisibleAmount()); SwingUtilities.invokeLater(new
Runnable() { public void run() {
vertical.setValue(vertical.getMaximum()); } }); if (sirCitit.equals(new String("."))) System.exit(0); // Conditie oprire }
} public void run () { String mesaj; while (true) { mesaj = conexiune.nextLine(); outTextGrafic.append("S-a primit: " +
mesaj + "\n"); // actualizeaza pozitia barei
de defilare, varianta imbunatatita a //
vertical.setValue(vertical.getMaximum() - vertical.getVisibleAmount()); SwingUtilities.invokeLater(new Runnable() { public void run() {
vertical.setValue(vertical.getMaximum()); } }); if (mesaj.equals("."))
break; // Testarea conditiei de
oprire } try {
socketTCP.close();
// Inchiderea socketului si a fluxurilor } catch (IOException ex) {} JOptionPane.showMessageDialog(null,
"Server: Bye!"); } public static void main (String args[]) throws IOException { ServerBidirectionalSwing
server = new ServerBidirectionalSwing(); new Thread(server).start(); } } |
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). |
In laborator: 1. Lansati in executie BlueJ. Inchideti proiectele anterioare. Creati
un proiect socketSwing 2. In proiectul socket creati
cele 4 clase ale caror coduri sunt date mai sus. Compilati codurile. 3. Testati sistemul ca la laboratorul anterior. |
In laborator: 1. La unul dintre calculatoare right-click pe clasa ServerBidirectionalSwing.
2. Selectati si executati main(). Folositi
numarul de port 3000. 3. La un alt calculator (daca nu aveti
la dispozitie un alt calculator in retea, deschideti inca o sesiune BlueJ)
right-click
pe clasa ClientBidirectionalSwing,
selectati si executati main().
4. Folositi adresa primului calculator,
pe care se executa ServerBidirectionalSwing
(adresa "localhost" in cazul in care folositi doua sesiuni
BlueJ pe acelasi calculator), si numarul de port 3000. 5. Urmariti efectul la client si la server. |
Clasa utilitara DialogUtilizator incapsuleaza
tratarea interactiunii cu utilizatorul (GUI):
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 |
import
javax.swing.JOptionPane; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class DialogUtilizator extends JFrame { private JTextField inTextGrafic; //
Intrare - linie de text grafica (JtextField) private JTextArea outTextGrafic; // Iesire - zona de text grafica
(JtextArea) private JScrollBar vertical; private ConexiuneRetea conexiune; private String sirCitit; String nume; // Initializari grafice public
DialogUtilizator(String nume) {
// constructor super(nume); // Stabilire titlu fereastra (JFrame) this.nume =
nume; Container containerCurent =
this.getContentPane(); containerCurent.setLayout(new
BorderLayout()); // Zona de text non-editabila de
iesire (cu posibilitati de defilare) outTextGrafic = new JTextArea(5, 40); JScrollPane scrollPane = new
JScrollPane(outTextGrafic,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); vertical =
scrollPane.getVerticalScrollBar(); containerCurent.add("Center",
scrollPane); outTextGrafic.setEditable(false); // Camp de text editabil de intrare inTextGrafic = new JTextField(40);
containerCurent.add("South", inTextGrafic); // Inregistrarea "ascultatorului"
de "evenimente actionare" la // "obiectul sursa" intrare
de text inTextGrafic.addActionListener(new
AscultatorInText()); // Iesire din program la inchiderea
ferestrei
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); // Impachetarea (compactarea)
componentelor in container setVisible(true); // Fereastra devine vizibila inTextGrafic.requestFocus(); //
Cerere focus pe intrarea de text } public String nextLine() { String linie =
inTextGrafic.getText(); // Citirea
unei linii text
inTextGrafic.setText(""); // Golirea intrarii text return linie; } public void printLine(String text) { outTextGrafic.append(text +
"\n");
vertical.setValue(vertical.getMaximum() -
vertical.getVisibleAmount()); validate(); repaint(); } public void setConexiune(ConexiuneRetea conexiune) { this.conexiune = conexiune; } class
AscultatorInText implements ActionListener { // Tratarea actionarii intrarii de
text (introducerii unui "Enter") public void
actionPerformed(ActionEvent ev) { sirCitit = nextLine();
conexiune.printLine(nume + ": " + sirCitit); if (sirCitit.equals(new
String("BYE"))) System.exit(0); //Conditie oprire }
} } |
Clasa utilitara ConexiuneRetea incapsuleaza
tratarea conexiunilor TCP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import java.net.*; import java.io.*; import java.util.Scanner;
public class ConexiuneRetea{ Socket conexiune; Scanner scannerTCP; PrintStream printerTCP;
public ConexiuneRetea(Socket conexiune) throws IOException { this.conexiune = conexiune; this.scannerTCP = new Scanner(conexiune.getInputStream()); this.printerTCP = new PrintStream(conexiune.getOutputStream()); } public void printLine(String text) { this.printerTCP.println(text); this.printerTCP.flush(); }
} |
Clasa ServerChatN2N reprezinta serverul
TCP care poate trata mai multi clienti:
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 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ServerChatN2N extends Thread { private static int numarClienti = 0; private static int portTCP; private static ServerSocket serverTCP; private static Socket socketTCP; public static final int NUMAR_MAXIM_CLIENTI = 10; private static ConexiuneRetea[] conexiuni; private int numarulConexiuniiCurente; // incepe cu 0
public ServerChatN2N(int numarulConexiuniiCurente) throws IOException { this.numarulConexiuniiCurente = numarulConexiuniiCurente; } public static void main (String args[]) throws IOException { conexiuni = new ConexiuneRetea[NUMAR_MAXIM_CLIENTI]; portTCP=Integer.parseInt(JOptionPane.showInputDialog("Introduceti port server")); serverTCP = new ServerSocket(portTCP); // Creare socket server while (true) { socketTCP = serverTCP.accept(); // Creare socket conexiuni[numarClienti] = new ConexiuneRetea(socketTCP); ServerChatN2N server = new ServerChatN2N(numarClienti++); server.start(); } } public void removeConnexion(int crt) { for (int i=crt; i<numarClienti-1; i++) { conexiuni[i] = conexiuni[i+1]; } numarClienti--; } public void run() { // Fir executie receptie prin socket String mesaj; while(true) { if (this.conexiuni[numarulConexiuniiCurente].scannerTCP.hasNextLine()){ mesaj = this.conexiuni[numarulConexiuniiCurente].scannerTCP.nextLine(); for (int i=0; i<numarClienti; i++) { conexiuni[i].printLine(mesaj); } if (mesaj.equals("BYE")) { removeConnexion(numarulConexiuniiCurente); } } try { sleep(1000); } catch (InterruptedException e) {} } } } |
Clasa ClientChatN2N reprezinta clientul
TCP cu interfata grafica:
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 |
import java.net.*; import java.io.*; import javax.swing.JOptionPane;
public class ClientChatN2N extends Thread { private ConexiuneRetea conexiune; private Socket socketTCP; private int portTCP; private InetAddress adresaIP; DialogUtilizator dialog; String numeClient;
public ClientChatN2N() throws IOException { portTCP=Integer.parseInt(JOptionPane.showInputDialog("Introduceti port server")); adresaIP=InetAddress.getByName( JOptionPane.showInputDialog("Introduceti IP server")); numeClient = JOptionPane.showInputDialog("Introduceti un nickname"); dialog = new DialogUtilizator(numeClient);
socketTCP = new Socket(adresaIP, portTCP); // Creare socket conexiune = new ConexiuneRetea(socketTCP); dialog.printLine("\nPentru oprire introduceti \"BYE\" si <Enter>\n"); }
public static void main (String args[]) throws IOException { ClientChatN2N client = new ClientChatN2N(); client.dialog.setConexiune(client.conexiune); client.start(); }
public void run() { // Fir executie receptie prin socket String mesaj; while(true) { if (this.conexiune.scannerTCP.hasNextLine()){ mesaj = this.conexiune.scannerTCP.nextLine(); this.dialog.printLine(mesaj); if (mesaj.equals("BYE")) break; // Testarea conditiei de oprire } try { sleep(1000); } catch (InterruptedException e) {} } try { this.socketTCP.close(); // Inchidere socket (implicit fluxuri) } catch (IOException ioe) {};
this.dialog.printLine("Bye!"); System.exit(0); } } |
In laborator: 1. Lansati in
executie BlueJ. Inchideti proiectele anterioare (Ctrl+W). Creati un proiect chatn2n 2. Creati cele 4 clase ale caror coduri sunt date mai sus. Compilati codurile. |
Optional, in laborator: 1. La unul dintre
calculatoare right-click pe
clasa ServerChatN2N. Selectati si executati main(). Folositi numarul de port 4000. La
alte 2-3 calculatoare (daca nu aveti la
dispozitie un alt calculator in retea, deschideti mai multe sesiuni BlueJ) right-click pe clasa Client ChatN2N, selectati si executati main().
Folositi adresa primului calculator (pe care se executa ServerChatN2N) si numarul de port 4000. |
Tema mini-proiectului este: Sistem de comunicatie (avansat, pentru
bonus) client-server (N-la-N) bazat pe socket TCP, fire de executie si
interfata grafica Swing pornind de la codurile sursa date ca exemplu la
acest laborator (NU de la zero!).
Proiectul va contine (pentru fiecare grup de studenti):
- dosarul
cu documentatia proiectului (6-8
pagini), incluzand:
- titlul proiectului si autorii – cu
indicarea rolului fiecaruia - prima
pagina
- descrierea claselor si metodelor utilizate (rol, structura,
comportament) - 3 pagini
- documentarea solutiilor tehnice care nu apar
in exemple, a problemelor intampinate,
- descrierea modului de utilizare al sistemului (cu screenshot-uri) – 2 pagini
- listingurile codurilor sursa
atasate ca anexa la dosar
- proiectul
in forma electronica (pe CD,
atasat de dosar cu un plic), continand:
- documentatia,
- codurile sursa ale proiectului si
- codurile sursa ale temelor de casa date
la lucrarile de laborator 1, 2, 3 si 4.
Sustinerea proiectului presupune:
- predarea
dosarului cu documentatia proiectului (avand atasata forma electronica)
- prezentarea
executiei sistemului daca acesta include
facilitati noi, avansate (pentru bonus)
- prezentarea
rolului fiecarui autor la realizarea sistemului si a documentarii lui
- prezentarea
solutiilor tehnice noi (pentru bonus)
- raspunsuri
la intrebari privind detalii ale proiectului (din documentatie si
listinguri)
Imbunatatiri / modificari posibile (pentru bonus) de la simplu la complex:
- adaugarea unui buton BYE
- interfata grafica si la server (ca
la client)
- imbunatatiri ale tratarii
exceptiilor
- canal privat intre 2 clienti
prin analiza lexicala
- canal privat intre 2 clienti
prin socket-uri noi
- lista utilizatori prosibili,
la server, si autentificare cu nume si
parola
- interfata grafica de monitorizare
la server
- inlocuirea tabloului conexiunilor cu Vector
- logfile la clienti si / server
pt. memorare dialog
- atasarea unor nickname-uri utilizatorilor
- difuzarea nickname-uri utilizatorilor
si afisarea unei liste participantilor
- invitarea / anuntarea potentialilor
utilizatori
- inlocuirea
socketurilor TCP cu socketuri UDP
- trecerea de la
client-server la un sistem
descentralizat