Sunteți pe pagina 1din 17

UNIVERSITATEA POLITEHNICA BUCURESTI

Facultatea de Electronica , Telecomunicatii si Tehnologia Informatiei

Proiect POO
Aplicatie Java: Minichat

Student :
Nedelcu Marius-Nicusor
Grupa 421 E
Profesor coordonator :
Popovici Eduard-Cristian

Bucuresti 2011

1. Introducere
Conceptul de baza folosit in acest proiect este acela de a implementa
un sistem de comunicatie, bazat pe un server si numerosi clienti conectati la
acesta.
Am dorit de asemenea sa implementez si numeroase alte functii utile
clientilor, cat si serverului, cum ar fi :
-adaugarea unui buton BYE
- interfata grafica si la server (ca la client)
- imbunatatiri ale tratarii exceptiilor
- atasarea unor nickname-uri utilizatorilor
-difuzarea nickname-uri utilizatorilor si afisarea unei liste participantilor
Pentru a inchide aplicatia din partea clientului sau a serverului,
aceasta nu se putea face decat prin tiparirea mesajul BYE si aplicatia se
inchidea impreuna cu socketurile si threadurile aferente.
Plecand de la codul initial, am dezvoltat aplicatia adaugandu-i
numeroase noi facilitati si imbunatatiri.

Imbunatatiri:
repararea erorilor proietului initial de la care am plecat
adaugarea unei conexiuni implicite asupra ferestrei clientului
cand o conexiune noua este creata, aceasta este adaugata in tabelul de
conexiuni cu indicele acelei conexiuni, pentru ca stergerea conexiunii
din tabela sa functioneze corespunzator, fara a afecta ceilalti clienti
sau a ocupa spatiu suplimentar in tabela
recrearea metodei public int nextInt care era nefunctionala

Noi facilitati:
adaugarea unui username pentru fiecare client
daca un client paraseste chat-ul, serverul nu primeste nici un mesaj de
eroare, ceilalti clienti nu au de suferit , ba mai mult fiecare va primi
un mesaj de tipul : <nume> a iesit !
daca serverul se inchide (fie prin trimiterea mesajului BYE, fie prin
apasarea butonului BYE) nici unuia dintre clientii conectati nu ii va
aparea un mesaj de eroare, ci va primi mesajul serverul a picat si
va fi deconectat
atunci cand un client nou se conecteaza/deconecteaza la/de la server,
serverul afiseaza un mesaj corespunzator si anunta toti clientii ca a
intrat/iesit un user
adaugarea unui buton pentru iesire din aplicatie care nu doar inchide
aplicatia, dar si anunta serverul in cazul clientului, ca acesta a iesit
care mai departe anunta toti clientii sau anunta clientii ca serverul a
fost oprit, acestia din urma fiind deconectati

Descrierea Claselor si Metodelor Utilizate


Clase utilizate: ClientChatN2N, ConexiuneRetea, DialogUtilizator, ,
ServerChatN2N

ClientChatN2N.java
Descriere clasa
Clasa extinde un obiect de tipul Thread, obiectul acesta se ocupa cu
firele de executie. Fiecare client va avea propiul lui fir de executie necesar
pentru a trimite si primi date catre si dinspre server.
Descriere constructor
Avem un constructor care primeste ca parametrii numele userului,
portul serverului si adresa serverului la care se va conecta. Acesta creeaza un
socket catre server si o conexiune pe baza acestui socket care va deschide un
InputStream si un OutputStream si le va atribui clientului dupa care anunta
serverul ca s-a logat cu succes. Constructorul deasemenea arunca erorile in
consola, deoarece acestea pot aparea cand este creat un socket nou sau o
conexiune noua.
Descriere metoda run()

Incearca sa primeasca mesaje prin conexiune de la server si sa le


afiseze in fereastra.In cazul in care un client trimite mesajul BYE serverul
trmite tuturor celorlalti clienti mesajul <<nume client>> a iesit .In cazul
in care serverul se deconecteaza socketul deschis se inchide si se afiseaza un
mesaj corespunzator.

ConexiuneRetea.java
Descriere clasa
Clasa se ocupa de crearea conexiunilor serverului si clientilor, cat si
de preluarea datelor trimise de catre acestia, retransmiterea acestora,
returnarea adresei locale a conexiunii si returnarea adresei serverului la care
este un client conectat. Clasa deasemenea arunca erorile in consola,
deoarece acestea pot aparea cand este creat un nou InputStream sau
OutputStream.
Descriere constructor
Primeste ca parametru socketul asupra caruia va atribui un
InputStream si un OutputStream pentru a primi si trimite date mai departe.
Descriere metoda nextLine()
Intoarce un sir de caractere ce are valoarea preluata prin Scannerul(InputStream-ul) conexiunii curente asupra careia se face citirea.
Descriere metoda printLine()
Primeste ca parametru sirul de caractere care urmeaza a fi trimis.
Descriere metoda getLocalAddress()
Intoarce un sir de caractere ce reprezinta adresa locala la care este
socketul conexiunii curente conectat (adresa clientului).
Descriere metoda getRemoteAddress()
Intoarce un sir de caractere ce reprezinta adresa la care este socketul
conexiunii curente conectat (adresa serverului).

DialogUtilizator.java
Descriere clasa
Clasa extinde un obiect de tipul JFrame, obiectul acesta se ocupa cu
ferestrele. Practic cu ajutorul acestei clase este realizat GUI-ul serverului si
sunt interpretate diverse functii ale serverului, cat si actiuni specifice ale
butoanelor acestuia. Am adaugat aici un buton private JButton buton; si
numele utilizatorului .
Descriere constructor

Primeste ca parametrii numele si ip-ul clientului. Constructorul se


ocupa de realizarea ferestrei cu toate elementele acesteia
(campuri,butoane,etc), adaugarea actiunilor asupra campurilor ce necesita
acest lucru, si asupra tuturor butoanelor.
Descriere metoda nextLine()
Identica cu cea de la DialogServer.
Descriere metoda addNume(String n)
Adauga in lista din partea dreapta a interfetei numele clientului care s-a
conectat.
Descriere metoda removeNume(String n)
Sterge din lista care se afla in dreapta fiecarei interfete numele clientului
care a iesit.
Descriere obiect AscultatorInText
Este atribuit campului inTextGrafic de la care va prelua string-ul
atunci cand userul apasa pe tasta Enter si il va trimite prin intermediul
conexiunii catre toti clientii serverului. Daca sirul primit este BYE se va
incheia executia programului.

ServerChatN2N.java
Descriere clasa
Clasa ServerChatN2N reprezinta serverul. Acesta se foloseste de un
DialogUtilizator si de un socket de server (pentru a putea sta in starea de
Listen).
In momentul rularii (metoda main), acesta cere numarul de port pe care va
asculta. Este necesar ca sa nu mai fie deja folosit, intrucat o eroare va fi
afisata .
Dupa crearea socketului in stare de ascultare, se incepe o bucla infinita unde
se primesc conexiuni, si pentru fiecare client care doreste sa se conecteze se
adauga la vectorul de conexiuni, se construieste serverul si se ruleaza
Thread-ul pe care acesta se bazeaza..
Descriere metoda run()
Cand se conecteaza un client serverul trimite catre toti clientii logati
mesajul <<nume client>> s-a conectat la server .
Daca exista mesaje care asteapta sa fie primite, se primesc si se trimit la toti
clientii conectati, folosind un for.
Daca in schimb se primeste text-ul BYE, thread-ul se opreste si
conexiunea se elibereaza, serverul trimitand un mesaj tuturor clientilor (<<
nume client>> a iesit ).

Mod de functionare al chat-ului


Pentru initierea unei conferinte e necesara crearea unui ServerChatN2N
prin introducerea unui numar de port.

Serverul (ServerChatN2N)
Atunci cand se ruleaza server-ul apare mai intai o caseta de dialog care ne cere portul pe
care va rula serverul.

Dup aceea se apasa OK, apare fereastra principala a serverului:

In acest moment serverul este pregatit sa accepte conexiuni din partea clientilor care se
conecteaza la IP-ul si portul pe care este el deschis.

Clientul (ClientChatN2N)
Atunci cand se ruleaza client-ul apare mai intai o caseta de dialog care ne cere numele :

Apoi apare o caseta care ne cere portul pe care se va conecta clientul :

In final va aparea o caseta care va cere IP-ul serverului la care ne vom conecta:

Dupa ce dam OK :

Acum vom mai rula inca un client, pentru a vedea cum mesajele se propaga intre clienti,
cu ajutorul serverului.

Observam ca in dreapta ferestrei apar numele clientilor logati.


Observam ca serverul ne anunta cand cineva se conecteaza.

Daca cineva actioneaza butonul BYE sau introduce textul BYE si apasa Enter,
serverul trimite catre toti ceilalti utilizatori mesajul <<nume client>> a iesit !

Daca serverul pica , atunci toti clientii sunt anuntati ca serverul a picat

ANEXA
Listarea claselor
Clasa DialogUtilizator
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 JButton buton;
private JScrollBar vertical;
public JList lista;
private ConexiuneRetea conexiune;
private String sirCitit;
public String nume[];
private int nrNume;
public static final int NUMAR_MAXIM_CLIENTI = 10;

// Initializari grafice
public DialogUtilizator(String nume) {
// constructor
super(nume);
// Stabilire titlu fereastra (JFrame)
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);
// Container pentru buton si inTextGrafic
Container container = new Container();
container.setLayout(new BorderLayout());
containerCurent.add("South", container);
// Buton pentru terminare program
buton = new JButton("BYE");
buton.addActionListener(new AscultatorButon());
container.add("East", buton);
// lista utilizatori
this.nume = new String[NUMAR_MAXIM_CLIENTI];
lista = new JList(this.nume);
containerCurent.add("East", lista);
nrNume = 0;
// Camp de text editabil de intrare
inTextGrafic = new JTextField(40);
container.add("Center", 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();
inTextGrafic.setText("");
return linie;
}

// Citirea unei linii text

// Golirea intrarii text

public void addNume(String n) {


nume[nrNume] = n;
lista.setListData(nume);
repaint();
nrNume++;
}
public void removeNume(String n) {
int idx = -1;
for(int i =0 ; i<nrNume; i++)
if(nume[i].equals(n)) {
idx = i;
break;
}
if(idx == -1)
return;
for (int i=idx; i<nrNume-1; i++) {
nume[i] = nume[i+1];
}
nrNume--;
nume[nrNume] = "";
lista.setListData(nume);
repaint();
}
public int nextInt() {
String linie = inTextGrafic.getText();
inTextGrafic.setText("");

// Citirea unei linii text

// Golirea intrarii text

return Integer.parseInt(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;
}
// 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) {
String sirCitit = nextLine();
if (sirCitit.equals(new String("BYE"))) {
conexiune.printLine("BYE");
System.exit(0); //Conditie oprire
}
conexiune.printLine(sirCitit);
}
}
class AscultatorButon implements ActionListener {
public void actionPerformed(ActionEvent ev) {
conexiune.printLine("BYE");
System.exit(0); //Conditie oprire
}
}
}

Clasa ConexiuneRetea
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();
}
public String getLocalAddress() {
return conexiune.getLocalAddress().getHostAddress();
}
public String getRemoteAddress() {
return conexiune.getInetAddress().getHostAddress();
}
}

Clasa ServerChatN2N
import java.net.*;
import java.io.*;
import javax.swing.JOptionPane;
public class ServerChatN2N extends Thread {
private static int numarClienti = 0;
private static DialogUtilizator dialog;
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 static String[] nume;
private int numarulConexiuniiCurente; // incepe cu 0
public ServerChatN2N(int numarulConexiuniiCurente) throws IOException {
this.numarulConexiuniiCurente = numarulConexiuniiCurente;
}
public static void main (String args[]) throws IOException {
dialog = new DialogUtilizator("SERVER CHAT N2N");
conexiuni = new ConexiuneRetea[NUMAR_MAXIM_CLIENTI];
// dialog.nume = new String[NUMAR_MAXIM_CLIENTI];
portTCP = Integer.parseInt(JOptionPane.showInputDialog(
"Introduceti numarul de port al serverului"));
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];
dialog.nume[i] = dialog.nume[i+1];
}
numarClienti--;

dialog.nume[numarClienti] = "";
}
public void run() { // Fir executie receptie prin socket
String mesaj;
dialog.nume[numarulConexiuniiCurente] =
conexiuni[numarulConexiuniiCurente].nextLine();
dialog.printLine(dialog.nume[numarulConexiuniiCurente] + " s-a conectat la
server");
dialog.lista.setListData(dialog.nume);
conexiuni[numarulConexiuniiCurente].printLine(""+(numarClienti-1));
for(int i = 0; i < numarClienti; i++)
if(i != numarulConexiuniiCurente)
conexiuni[numarulConexiuniiCurente].printLine(dialog.nume[i]);
dialog.repaint();
for (int i=0; i<numarClienti; i++)
if(i != numarulConexiuniiCurente) {
conexiuni[i].printLine(dialog.nume[numarulConexiuniiCurente] + " s-a
conectat la server");
}
while(true) {
mesaj = this.conexiuni[numarulConexiuniiCurente].nextLine();
// Testarea conditiei de oprire
if (mesaj.equals("BYE")) {
for (int i=0; i<numarClienti; i++)
if(i != numarulConexiuniiCurente)
conexiuni[i].printLine(dialog.nume[numarulConexiuniiCurente] + " a iesit!");
this.dialog.printLine(dialog.nume[numarulConexiuniiCurente] + " a iesit!");
removeConnexion(numarulConexiuniiCurente);
this.stop();
}
// this.dialog.printLine(mesaj);
for (int i=0; i<numarClienti; i++) {
conexiuni[i].printLine(dialog.nume[numarulConexiuniiCurente] + " : " +
mesaj);
}
}
}

Clasa ClientChatN2N
import java.net.*;
import java.io.*;
import javax.swing.JOptionPane;
public class ClientChatN2N extends Thread {
private DialogUtilizator dialog;
private ConexiuneRetea conexiune;
private Socket socketTCP;
private int portTCP;
private InetAddress adresaIP;
private String nume;
public ClientChatN2N() throws IOException {
dialog = new DialogUtilizator("CLIENT CHAT N2N");
do {nume = JOptionPane.showInputDialog(
"Introduceti numele utilizatorului");
} while(nume.indexOf(':') != -1);
portTCP = Integer.parseInt(JOptionPane.showInputDialog(
"Introduceti numarul de port al serverului"));
adresaIP = InetAddress.getByName(JOptionPane.showInputDialog(
"Introduceti adresa IP a serverului"));
socketTCP = new Socket(adresaIP, portTCP); // Creare socket
conexiune = new ConexiuneRetea(socketTCP);
dialog.setConexiune(conexiune);
dialog.printLine("\nPentru oprire introduceti \"BYE\" si <Enter>\n");
}
public static void main (String args[]) throws IOException {
ClientChatN2N client = new ClientChatN2N();
client.start();
String mesaj;
client.dialog.printLine("Introduceti mesaje\n");
try {
client.start();
} catch(Exception e) {}
}

public void run() { // Fir executie receptie prin socket


String mesaj;
conexiune.printLine(nume);
dialog.addNume(nume);
int nr = Integer.parseInt(conexiune.nextLine());
for(int i = 0; i < nr; i++)
dialog.addNume(conexiune.nextLine());
while(true) {
try {
mesaj = this.conexiune.nextLine();
this.dialog.printLine(mesaj);
if (mesaj.trim().equals("BYE")) break; // Testarea conditiei de oprire
if(mesaj.indexOf(':') == -1){
int j = mesaj.indexOf(" s-a conectat la server");
if(j != -1)
dialog.addNume(mesaj.substring(0,j));
j = mesaj.indexOf(" a iesit!");
if(j != -1)
dialog.removeNume(mesaj.substring(0,j));
}
} catch (java.util.NoSuchElementException e){
this.dialog.printLine("Serverul a picat");
while(true);
}
}
try {
this.socketTCP.close(); // Inchidere socket (implicit fluxuri)
} catch (IOException ioe) {};
this.dialog.printLine("Bye!");
System.exit(0);
}
}

S-ar putea să vă placă și