Documente Academic
Documente Profesional
Documente Cultură
Proiect Licenta
Proiect Licenta
Lucrare de licență
Control de tip multi user pentru echipamente convenționale
folosind tehnici de tip remote
autorul lucrării
Control de tip multi user pentru echipamente convenționale folosind tehnici de
tip remote
1. Introducere
1.1. Context
1.2. Prezentarea pe scurt a aplicației
1.3. Descrierea capitolelor
2. Resurse software
2.1. Limbajul de programare JAVA
2.1.1. Noțiuni generale
2.1.2. Programare în rețea
2.1.3. Socket-uri
2.1.4.Threads
2.1.5. Swing
2.2. Intellij IDEA
3. Arhitectura aplicației
3.1. Module componente
3.2. Mod de funcționare
3.3. Modalități de dezvoltare
4. Concluzii
5. Bibliografie
6. Anexe
1. Introducere
1.1. Context
La nivel mondial se poate observa tendința de a automatiza majoritatea proceselor ce implică un
cadru de muncă monoton și activități repetitive. Pentru a crește eficiența, pentru a evita apariția
defectelor produse de om, dar și pentru a diminua cheltuielile dintr-o companie, prin micșorarea
numărului de angajați, se construiesc diferiți algoritmi ce imită anumite tipare, cu ajutorul cărora
să se înlocuiască o parte dintre meserii. [1]
Acest lucru nu este întotdeauna posibil, de aceea regăsim și astăzi unele locuri de muncă ce nu
pot fi înlocuite în totalitate de mașini, în schimb, pentru a ușura munca operatorilor ce trebuie să
administreze aparatura, se folosesc diferite aplicații ce permit controlul de la distanță a acestora.
Când vine vorba de aplicații, putem observa cum programatorii crează interfețe cât mai inedite cu
ajutorul cărora un utilizator poate controla cu ușurință anumiți parametri, fără a depune efort sau
fără să îi fie necesare cunoștințe avansate în prealabil.
Mare parte dintre aceste aplicații folosesc tehnologia client/server, ce prezintă posibilitatea de a
controla de la distanță, utilizatorul trimițând către “server” solicitarea de a se folosi de anumiți
parametri, urmând ca acesta să aștepte să primească confirmarea.
Diferite sisteme implementează rețele întregi de echipamente ce comunică între ele și pot fi setate
dintr-un singur computer, pentru a eficientiza modul în care sunt utilizate resursele, cât și pentru
fi mai ușor de urmărit și de asigurat mentenanța acestora.
În aplicația pe care urmează să o prezint, vom simula un sistem specific dispozitivelor de tip
HVAC (Heating, ventilation, and air conditioning), mai exact, un utilizator poate să aleagă o
anumită temperatură, umiditate, sau de ce nu, luminozitate, pentru a fi sigur că are parte de
condițiile optime de muncă
HVAC este o parte importantă a structurilor rezidențiale, cum ar fi casele unifamiliale, clădirile de
apartamente, hotelurile, clădirile industriale și de birouri de dimensiuni mari până la zgârie-nori și
spitale, vehicule precum mașini, trenuri, avioane, nave și submarine și în medii marine, unde
condițiile de construcție sigure și sănătoase sunt reglementate în ceea ce privește temperatura și
umiditatea, folosind aer proaspăt din aer liber.
Ventilarea sau ventilația este procesul de schimb sau de înlocuire a aerului în orice spațiu pentru a
oferi o calitate ridicată a aerului interior, care implică controlul temperaturii, reumplerea
oxigenului și eliminarea umidității, mirosurilor, fumului, căldurii, prafului, bacteriilor aeriene,
dioxid de carbon și alte gaze. Ventilarea elimină mirosurile neplăcute și umiditatea excesivă,
introduce aer exterior, menține circulația aerului din interior și previne stagnarea acestuia.
Deși HVAC este executat în clădiri individuale sau în alte spații închise, echipamentul implicat
este, în unele cazuri, o extindere a unei rețele de dispozitive. În astfel de cazuri, aspectele de
operare și întreținere sunt simplificate, iar contorizarea devine necesară pentru a factura energia
consumată și, în unele cazuri, energia care este returnată sistemului mai mare. De exemplu, la un
moment dat, o clădire poate utiliza apă rece pentru aer condiționat, iar apa caldă pe care o
returnează poate fi utilizată într-o altă clădire pentru încălzire.
Utilizarea HVAC pe o rețea mai mare ajută la asigurarea unei economii de scară care nu este adesea
posibilă pentru clădirile individuale, pentru utilizarea surselor de energie regenerabilă, cum ar fi
căldura solară, frigul de iarnă, potențialul de răcire în unele locuri de lacuri sau apă de mare pentru
răcire gratuită și funcția de activare a stocării sezoniere a energiei termice. [2]
Am ales să vorbesc despre acest topic deoarece reprezintă un domeniu de interes, iar după cum voi
prezenta și în capitolele următoare, sunt de părere că rețelele de comunicare între dispozitive vor
deveni tot mai avansate în anii ce vor urma, iar cunoștințele în ceea ce privește acest domeniu vor
fi indispensabile unui inginer.
Am folosit această tehnologie gândindu-mă că, într-o clădire precum sunt cele de birouri, există
un departament ce se ocupă de facilitățile de care au nevoie angajații. Având în vedere că spre
exemplu, într-un etaj pot să lucreze mai mulți oameni în funcție de departamentul în care activează,
sau, există anumite aparate ce au nevoie să fie întreținute în anumite condiții, vor avea nevoie de
altă temperatura, sau mai bine zis, de alți parametri care să le producă un mediu plăcut.
Cum angajații trebuie să se concentreze pe activitatea pe care o desfășoară, le vine în datoria celor
ce se ocupă de facilități să se asigure că toate condițiile de muncă sunt îndeplinite.
Această aplicație simulează această activitate prin faptul că redă comunicarea în rețea a
dispozitivelor de aer condiționat, ce sunt conectate la un server ce se asigură că acestea sunt în uz
în momentul în care în clădire se lucrează.
Aplicația este formată din două module, ChatServer și ChatUser, fiecare fiind compusă din trei,
respectiv șase clase. ChatServer l-am denumit în cadrul proiectului “localhost” și comunică cu
ceilalți clienți prin portul 8818. ChatUser pentru a se conecta la server, are impusă condiția de a se
folosi de un nume de utilizator și o parolă, ambele fiind prestabilite.
Am creat o interfață cu ajutorul Java Swing, care să arate câte dispozitive sunt conectate la server,
deși, pentru a simula comunicarea cu un client, la început am folosit comanda “telnet” în Command
Prompt.
Un utilizator va trimite solicitarea către server, iar iar în același timp, ceilalți clienți conectați vor
fi capabili să vadă solicitarea nou creată.
Atât despre tehnologiile folosite, cât și despre componentele aplicației voi dezvolta în capitolele
ce urmează.
Capitolul 2. În acest capitol am prezentat resursele software ce mi-au fost necesare în realizarea
acestei lucrări. Am prezentat limbajul de programare JAVA și descris pe scurt conceptele de care
m-am folosit în realizarea aplicației . Am prezentat mediul de dezvoltare Intellij IDEA pe care l-
am folosit la compilare.
Capitolul 3. Aici am descris arhitectura lucrării și i-am prezentat funcționalitatea. Am vorbit despre
fiecare componentă și despre metodele utilizate. Am prezentat și posibilitățile de scalare ale
aplicației sau industriile unde este implementată această tehnologie.
Capitolul 4. Sunt prezentate concluziile cu care am rămas după întocmirea acestei lucrări. Am
prezentat pe scurt și modul în care voi continua să dezvolt aplicația.
2. Tehnologii folosite
Limbajul de programare Java a fost folosit la dezvoltarea unor tehnologii dedicate rezolvării unor
probleme din cele mai diverse domenii. Aceste tehnologii au fost grupate în așa numitele platforme
de lucru, ce reprezintă seturi de librării scrise în limbajul Java, precum și diverse programe utilitare,
folosite pentru dezvoltarea de aplicații sau componente destinate unei anume categorii de
utilizatori.
Clasele din acest pachet oferă o modalitate facilă de programare în rețea, fără a fi nevoie de
cunoștințe prealabile referitoare la comunicarea efectivă între calculatoare. Cu toate acestea, sunt
necesare câteva noțiuni fundamentale referitoare la rețele cum ar fi: protocol, adresa IP, port,
socket.
- UDP (User Datagram Protocol) este un protocol bazat pe pachete independente de date, numite
datagrame, trimise de la un calculator către altul fără a se garanta în vreun fel ajungerea acestora
la destinație sau ordinea în care acestea ajung. Acest protocol nu stabilește o conexiune permanentă
între cele două calculatoare.
2.1.3. Socket-uri
Un socket (soclu) este o abstracțiune software folosită pentru a reprezenta fiecare din cele două
”capete” ale unei conexiuni între două procese ce rulează într-o rețea. Fiecare socket este atașat
unui port astfel încât să poată identifica unic programul căruia îi sunt destinate datele.
Programele de tip server sunt cele care oferă diverse servicii eventualilor clienți, fiind în stare de
așteptare atâta vreme cât niciun client nu le solicită serviciile. Programele de tip client sunt cele
care inițiază conversația cu un server, solicitând un anumit serviciu. Uzual, un server trebuie să fie
capabil să trateze mai mulți clienți simultan ¸și, din acest motiv, fiecare cerere adresată serverului
va fi tratată într-un fir de execuție separat.
Legătura între un client și un server se realizează prin intermediul a două obiecte de tip Socket,
câte unul pentru fiecare capăt al ”canalului” de comunicație dintre cei doi. La nivelul clientului
crearea socketului se realizează specificând adresa IP a serverului și portul la care rulează acesta,
constructorul uzual folosit fiind:
La nivelul serverului, acesta trebuie să creeze întâi un obiect de tip ServerSocket. Acest tip de
socket nu asigură comunicarea efectivă cu clienții ci este responsabil cu ”ascultarea” rețelei și
crearea unor obiecte de tip Socket pentru fiecare cerere apărută, prin intermediul căruia va fi
realizată legătura cu clientul. Crearea unui obiect de tip ServerSocket se face specificând portul la
care rulează serverul, constructorul folosit fiind:
ServerSocket(int port)
Metoda clasei ServerSocket care așteaptă ”ascultă” rețeaua este accept. Această blochează
procesul părinte până la apariția unui cereri și returnează un nou obiect de tip Socket ce va asigura
comunicarea cu clientul. Blocarea poate să nu fie permanentă ci doar pentru o anumită perioada
de timp - aceasta va fi specificată prin metoda setSoTimeout, cu argumentul dat în milisecunde.
Pentru fiecare din cele două socket-uri deschise pot fi create apoi două fluxuri pe octeți pentru
citirea, respectiv scrierea datelor. Acest lucru se realizează prin intermediul metodelor
getInputStream, respectiv getOutputStream. Fluxurile obținute vor fi folosite împreună cu fluxuri
de procesare care să asigure o comunicare facilă între cele două procese. În funcție de specificul
aplicației acestea pot fi perechile:
2.1.4. Threads
Firele de execuție fac trecerea de la programarea secvențială la programarea concurentă. Un
program secvențial reprezintă modelul clasic de program: are un început, o secvență de execuție a
instrucțiunilor sale și un sfârșit. Cu alte cuvinte, la un moment dat programul are un singur punct
de execuție. Un program aflat în execuție se numește proces. Un sistem de operare monotasking,
cum ar fi fi MS-DOS, nu este capabil să execute decât un singur proces la un moment dat, în timp
ce un sistem de operare multitasking, cum ar fi UNIX sau Windows, poate rula oricâte procese în
același timp (concurent), folosind diverse strategii de alocare a procesorului fiecăruia dintre
acestea.
Un fir de execuție este similar unui proces secvențial, în sensul că are un început, o secvență de
execuție și un sfârșit. Diferența dintre un fir de execuție și un proces constă în faptul că un fir de
execuție nu poate rula independent ci trebuie să ruleze în cadrul unui proces.
Ca orice alt obiect Java, un fir de execuție este o instanță a unei clase. Firele de execuție definite
de o clasă vor avea același cod și, prin urmare, aceeași secvență de instrucțiuni. Crearea unei clase
care să definească fire de execuție poate fi făcută prin două modalități:
- prin extinderea clasei Thread
Cea mai simplă metodă de a crea un fir de execuție care să realizeze o anumită acțiune este prin
extinderea clasei Thread și supradefinirea metodei run a acesteia. Formatul general al unei astfel
de clase este:
super(nume);
...
Prima metodă a clasei este constructorul, care primește ca argument un șir ce va reprezenta numele
firului de execuție. În cazul în care nu vrem să dăm nume firelor pe care le creăm, atunci putem
renunța la supradefinirea acestui constructor și să folosim constructorul implicit, fără argumente,
care creează un fir de execuție fără niciun nume. Ulterior, acesta poate primi un nume cu metodă
setName. Evident, se pot defini și alți constructori, aceștia fiind utili atunci când vrem să trimitem
diverși parametri de inițializare firului nostru. A doua metodă este metoda run, ”inima” oricărui
fir de execuție, în care scriem efectiv codul care trebuie să se execute.
Un fir de execuție creat nu este automat pornit, lansarea să fiind realizată de metodă start, definită
în clasa Thread.
// Lansăm în execuție
fir.start();
2.1.5. Swing
Tehnologia Swing face parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) care
pune la dispoziție o serie întreagă de facilități pentru scrierea de aplicații cu o interfață grafică
mult îmbogățită funcțional și estetic față de vechiul model AWT.
Unul din principalele obiective ale tehnologiei Swing a fost să pună la dispoziție un set de
componente GUI extensibile care să permită dezvoltarea rapidă de aplicații Java cu interfață
grafică competitivă din punct de vedere comercial. Pentru a realiza acest lucru, API-ul oferit de
Swing este deosebit de complex având 17 pachete în care se găsesc sute de clase și interfețe, cel
mai important și care conține componentele de baza fiind javax.swing.[3]
- drept memorie RAM, sunt necesari minim 2 GB sau 8 GB pentru un developer Android;
IntelliJ IDEA oferă anumite caracteristici cum ar fi completarea codului prin analizarea
contextului, navigarea codului, care permite saltul la o clasă, refactorizarea codului, alinarea și
opțiunile pentru a remedia inconsecvențele prin sugestii.
Suporta sisteme de control a versiunilor precum Git, Mercurial, Perforce și SVN. Baze de date
precum Microsoft SQL Server, Oracle, PostgreSQL, SQLite și MySQL pot fi accesate direct de la
IDE în ediția Ultimate.[4]
3. Arhitectura aplicației
Proiectul este compus din două module, ChatServer, care descrie modul în care acționează
serverul, și ChatClient, cel care asigura comunicarea cu acesta.
Am atașat mai jos o captura unde sunt afișate cele două module împreună cu interfețele și clasele
din care sunt formate.
Fig. 1. Meniul ce conține cele două module și clasele asociate acestora
ChatServer este format din trei clase componente: ServerMain, ServerWorker și Server, pe când
ChatClient conține patru clase și două interfețe: ChatClient, UserListPane, LoginWindow,
MessagePane, UserStatusListener și MessageListener.
Clasa ServerMain conține metoda principală main(), în care am declarat portul, am creat un
constructor care să facă legătura cu celelalte clase din pachet și am pornit firul de execuție. Pentru
a nu o încărca, am adăugat în celelalte clase metodele prin care se realizează comunicarea cu
utilizatorii conectați la server. Am atașat mai jos codul acesteia.
package main.java.com.muc;
Clasele ServerWorker și Server conțin cele mai importante metode deoarece acestea fac legătura
cu utilizatorii.
}
}
clientSocket.close();
}
În realizarea aplicației am avut nevoie și de o librărie de la Apache, apache commons lang 3.9, cu
ajutorul căreia am putut folosi comanda StringUtils.split, ce împarte un String, în cazul nostru
“tokens”, într-o arie de alte Stringuri.[5]
Metoda handleLogin cuprinde cele două seturi de date de autentificare, totodată fiind atașate și
condițiile necesare ca un utilizator să poată vedea statusul unui utilizator care se conectează sau se
deconectează de la server.
Clasa Server conține metoda care face legătura cu ceilalți clienți și prin care serverul așteaptă să
primească un mesaj de la utilizatori, și anume “accept()”. Am atașat mai jos secvența ce cuprinde
această metodă.
În ceea ce privește modulul ChatClient, acesta cuprinde două interfețe ce simplifică anumite
procese pe care urmează să le prezint, și alte patru clase din care trei dintre ele conțin metodă
principală main(). Fiecăreia i-am creat posibilitatea de a se conecta la server folosind setul de date
de autentificare “guest”. Dintre acestea, UserListPane și LoginWindow au și o interfață realizată
cu ajutorul Java Swing ce apare în momentul rulării.
Clasa ChatClient cuprinde o serie de metode ce facilitează comunicarea cu serverul. Cu ajutorul
acestei clase, utilizatorul primește notificări în momentul în care un alt client se conectează la
server, sau este anunțat în caz de un alt utilizator încearcă să comunice cu acesta.
Pentru a se conecta la server, am creat metoda “connect” pe care am prezentat-o mai jos.
Prin această secvență, utilizatorul primește și trimite informații către server. În capitolul următor
voi prezenta și modul în care lucrează cu ceilalți utilizatori.
În clasa UserListPane am folosit pentru prima dată tehnologia Swing, pentru a crea o listă unde să
fie afișați toți utilizatorii conectați în acel moment la server. Sunt de părere că se mai poate lucra
la ea, și pentru a induce mai mult ideea de sistem cu dispozitive HVAC integrate, ar putea să fie
afișați toți utilizatorii ce trebuie conectați la server, împreună cu statusul în care se află, fie online,
fie offline.
Fereastra unde sunt afișați utilizatorii este prezentată prin programul afișat mai jos.
frame.getContentPane().add(userListPane, BorderLayout.CENTER);
frame.setVisible(true);
if (client.connect()) {
try {
client.login("guest", "guest");
} catch (IOException e) {
e.printStackTrace();
}
}
}
În clasa LoginWindow am adăugat o opțiune în plus, și anume i-am creat utilizatorului posibilitatea
de a se conecta introducând datele de autentificare într-o fereastră separată, în celelalte clase acest
lucru realizându-se în terminal, cu setul de date de autentificare “guest”.
Această fereastră înlocuiește interfața creată cu ajutorul comenzii “telnet” în Command Prompt,
în schimb, nu reușește să ilustreze comunicarea la fel de bine. Codul pentru fereastra respectivă l-
am atașat mai jos.
public LoginWindow() {
super("Login");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
loginButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doLogin();
}
});
getContentPane().add(p, BorderLayout.CENTER);
pack();
setVisible(true);
}
UserStatusListener reprezintă interfața ce dă statusul pe care îl are un utilizator, în cazul în care
acesta este conectat la server. Am folosit-o pentru a afișa statusul în cadrul ferestrei create în
clasele UserListPane și LoginWindow. Atunci când un utilizator se conectează la server, acesta va
fi afișat în fereastră, iar atunci când se va deconecta, utilizatorul va dispărea.
package com.muc;
package com.muc;
Pentru a avea mai mult control, m-am gândit că ar fi indicat impun condiția că userii să se conecteze
printr-un set de date de autentificare prestabilite. Seturile de date introduse momentan în aplicație
sunt “guest” și “alind”, acestea fiind folosite atât pentru numele de utilizator, cât și pentru parolă.
Bineînțeles că acestea ar putea fi schimbate în “parter” și “etaj1” în caz de vrem să facem referire
la o clădire, sau de ce nu, să se impună o condiție cu ajutorul căreia să se conecteze mai mulți
utilizatori.
Pentru a afișa comunicarea dintre utilizatori, am folosit comanda “telnet” in Command Prompt.
Telnet este un protocol de rețea care oferă o interfață de linie de comandă pentru a comunica cu
un dispozitiv. Este utilizat cel mai adesea pentru gestionarea de la distanță, dar și uneori pentru
configurarea inițială pentru unele dispozitive, în special hardware-ul de rețea, cum ar fi switch-
urile și punctele de acces. Telnet este de asemenea utilizat pentru a gestiona fișierele de pe un site
web.
Telnet a fost folosit inițial pe terminale. Aceste computere necesită doar o tastatură, deoarece totul
pe ecran se afișează ca text. Terminalul oferă o modalitate de a te conecta de la distanță la un alt
dispozitiv, la fel ca și cum ai fi așezat în fața lui și l-ai folosi ca orice alt computer.
În zilele noastre, Telnet poate fi utilizat de la un terminal virtual, sau un emulator de terminale,
care este în esență un computer modern care comunică cu același protocol Telnet. Un exemplu în
acest sens este comanda telnet, disponibilă de la promptul de comandă din Windows. Comanda
telnet utilizează protocolul Telnet pentru a comunica cu un dispozitiv sau sistem de la distanță.
Comenzile Telnet pot fi executate și pe alte sisteme de operare, cum ar fi Linux, Mac și Unix, în
același mod în care sunt executate comenzi telnet în Windows.
Telnet nu este la fel ca alte protocoale TCP / IP, cum ar fi HTTP, care transferă fișierele către și
de pe un server. În schimb, protocolul Telnet vă permite să vă conectați la un server ca și cum ați
fi un utilizator efectiv, apoi vă acordă controlul direct și toate aceleași drepturi asupra fișierelor și
aplicațiilor ca și utilizatorul la care v-ați autentificat.[6]
În ServerWorker am introdus o metodă prin care să se comunice pe un anumit topic folosind tasta
“#” în fața cuvântului ce introduce topicul de discuție. După cum se poate vedea mai jos, am ilustrat
pentru fiecare dintre parametrii reprezentanți ai dispozitivelor de tip HVAC, temperatura și
umiditatea, dar și luminozitate, deoarece reprezintă un factor de importantă atunci când facem
referire la facilitățile de care au nevoie angajații. Metodele cu ajutorul cărora am realizat ideea de
solicitarea de schimbare a unui parametru le-am atașat mai jos.
} else {
if (sendTo.equalsIgnoreCase(worker.getLogin())) {
String outMsg = "msg " + login + " " + body + "\n";
worker.send(outMsg);
}
}
}
}
Pentru a folosi aceste metode am instantiat un HashSet, sub denumirea de topicSet. HashSet
implementează interfața Set, susținută de o instanță HashMap. Nu oferă garanții cu privire la
ordinea de iterație a setului; în special, nu garantează dacă o comandă va rămâne constantă în timp.
Această clasă permite elementul null.
Această clasă oferă performanțe de timp constante pentru operațiunile de bază (add, remove,
contain și size), presupunând că funcția de hash împrăștie elementele în mod corespunzător.
Iterarea acestui set necesită timp proporțional cu suma dimensiunii instanței HashSet (numărul de
elemente), plus "capacitatea" instanței HashMap de rezervă. [7]
În același fel, putem trimite un mesaj prin care anunțăm că modificăm umiditatea, după cum am
afișat mai jos.
După cum prezentat și mai devreme, am atașat o captură ce surprinde și modificarea luminozității.
Fig. 8. Controlul luminozității
Pentru a realiza aceste lucruri, nu avem nevoie de ajutorul altei clase, deoarece “telnet” ne pune la
dispoziție această interfață ce simulează clientul.
Cu toate acestea, am vrut să construiesc o clasă ce va face același lucru, iar aici intervine modulul
ChatClient.
După cum am prezentat anterior, acest modul conține trei clase ce interacționează cu serverul, iar
în continuare, voi descrie ceea ce este afișat în terminal, sau, în cazul claselor UserListPane și
LoginWindow, voi atașa capturi cu ferestrele create cu ajutorul Java Swing.
Clasa ChatClient, a fost prima clasa creată cu scopul de a comunica cu serverul. După cum am
prezentat și anterior, aceasta se folosește de setul de date “guest” pentru a se conecta la server. În
momentul în care o rulăm, în terminal va fi afișată următoarea secvență:
client.addMessageListener(new MessageListener() {
@Override
public void onMessage(String fromLogin, String msgBody) {
System.out.println("You got a message from: " + fromLogin + " ==> " + msgBody);
}
});
După cum se poate vedea mai jos, în momentul în care am trimis un mesaj utilizatorului cu setul
de date “guest”, acesta a apărut și în terminal, împreună cu numele utilizatorului de la care provine.
UserListPane este prima clasa în care m-am folosit de Java Swing pentru a crea o interfață. În
momentul rulării, în terminal va fi afișat următorul mesaj:
Fig. 11. Mesaj afișat în terminal
Totodată, un utilizator se conectează utilizând setul de date “guest”, iar dacă nu am mai rulat nicio
altă clasa și ceilalți utilizatori sunt deconectați, pe ecran va apărea fereastra de mai jos, fără să
conțină vreun nume afișat. Aici ar trebui să adaug anumite modificări, deoarece un utilizator nu
poate să se vadă pe el în acea listă, lucru care nu se întâmplă într-o rețea de dispozitive HVAC.
Pe lângă asta, ar putea fi introduse toate dispozitivele ce sunt sau care ar trebui conectate la server,
împreună cu statusul în care se află, fie online, fie offline.
Fig. 12. Fereastra aparuta dupa rularea clasei UserListPane
Diferența cu care vine în plus clasa LoginWindow este că, atunci când o rulăm, va apărea
următoarea fereastră unde va trebui să introducem datele de autentificare:
Fig. 13. Interfața unde se pot introduce datele de logare
În captura de mai jos vedem un utilizator conectat deoarece am folosit în prealabil setul de date
“alind” prin telnet, iar acum, introducând setul de date “guest”, am regăsit celălalt utilizator
conectat la server.
Fig. 14. Interfața unde sunt afișați ceilalți utilizatori
Așadar, acum că am parcurs toate clasele ce fac parte din modulul ChatClient, putem spune că am
risipit toate metodele create, care să producă o legătură între server și utilizatori.
Aplicația în sine poate fi dezvoltată prin asocierea cu o baza de date care să salveze aceste
informații, cât și prin implementarea unor metode de a crea anumite rapoarte unde să se afle
temperatura medie într-o zi, poate să se facă o comparație între anotimpuri (spre exemplu:
comparația între vară și iarnă), astfel să se tragă anumite concluzii și să se caute metode prin care
să fie economisită energie.
Am putea primi informații cu privire la starea în care se află, dacă răspunde sau nu la comenzile
serverului, pentru a ști dacă un dispozitiv se află în stare de bună funcționare.
Pentru a îmbunătăți aplicația ar putea fi setate anumite condiții în cod cum ar fi, în caz că se
depășește o anumită valoare, severul să nu accepte (spre exemplu: să nu fie de acord să fie setată
o temperatura de peste 30 de grade, dacă în acea încăpere lucrează oameni), atunci când userul se
conectează la server, să fie întrebat căror parametri dorește să le schimbe valoarea.
Acestea reprezintă doar câteva modalități prin care mă gândesc că aplicația ar putea fi îmbunătățită,
și totodată, prin aceste modificări ar putea induce și mai mult ideea de sistem ce simulează
comunicarea între un server și dispozitive de tip HVAC. Acesta e și scopul meu pe viitor, să
dezvolt și mai mult acest proiect pentru a-l face cât mai compact și totodată, să-mi îmbogățesc
cunoștințele pe care le-am dobândit în timp ce l-am realizat.
Această aplicație reprezintă doar o simulare, însă acest este deja dezvoltat cu succes cu ajutorul
unor tehnologii pe care le-am prezentat în mare mai jos. Cu ajutorul lor au fost create rețele de
dispozitive ce comunică și distribuie informații către server.
JACE (Java Application Control Engine) – Pentru a integra sisteme diverse, este necesară o
conexiune fizică la rețeaua unui dispozitiv. Un JACE este un mecanism / dispozitiv care asigură
conectivitate la sisteme (HVAC, electric, chiar și securitate în unele cazuri) în cadrul unei mașini
cu ajutorul Niagara Framework, care permite driverelor să integreze sisteme de control pentru o
gama mare de producători. Prin conectarea protocoalelor de rețea comune, cum ar fi LonWorks,
BACnet și Modbus, împreună cu multe rețele proprii, apare un sistem compact. Un JACE poate
găzdui, de asemenea, interfața utilizatorului cu sistemul de control în multe cazuri.
BACnet (Building Automation and Control networks) – a fost realizat pentru a permite
comunicarea construcțiilor automate și a sistemelor de control pentru aplicații precum încălzirea,
ventilarea, și controlul aerului condiționat (HVAC), controlul iluminatului, controlul accesului și
în cazul sistemelor de detectare a incendiilor și echipamentele asociate acestora. Protocolul
BACnet oferă mecanisme pentru dispozitivele automatizate să facă schimb de informații,
indiferent de serviciul pe care îl oferă.[9]
Am atașat o schemă ce prezintă în mare modul în care funcționează un sistem ce are JACE integrat:
Proiectul acesta m-a ajutat să-mi îmbogățesc cunoștințele de Java și totodată, prin realizarea acestei
aplicații m-am familiarizat cu acest concept, aplicațiile de tip client/server. Suntem în secolul
vitezei, iar căile de comunicare se doresc a fi cât mai rapide și bine întreținute pentru a putea
distribui eficient informația. Comunicarea dintre un server și dispozitivele asociate ușurează modul
de operare al acestora, plus că ajută și la monitorizare, deoarece dacă un dispozitiv nu apare în
sistem, lipsa acestuia este sesizată, așa că este mai simplu de asigurat și mentenanța acestora.
Cu toate că aplicația reușește să simuleze modul în care comunică dispozitivele de tip HVAC cu
un server, sunt de părere că poate fi mult îmbunătățită. După cum am prezentat mai sus, pe lângă
asocierea cu o baza de date unde să fie stocate anumite informații, sunt anumite condiții ce ar putea
fi adăugate în cod pentru a crea anumite limitări în ceea ce privește gama de parametri ce urmează
a fi setați. Aplicația are momentan destul de multe bug-uri ce pot fi înlăturate, în schimb pentru a
fi cât mai compactă, mai trebuie dezvoltată.
Acesta reprezintă și scopul meu în momentul de față, pentru a-mi finaliza lucrarea, sunt conștient
că are nevoie de mai multe îmbunătățiri și de aceea îmi propun ca pe viitor să implementez
schimbările pe care le-am menționat, și poate să mă folosesc și de anumite metode mai eficiente,
pentru a nu încarcă foarte mult proiectul. Îmi propun să creez și o interfață ceva mai prietenoasă și
care să-mi permită interacționez mai mult cu serverul.
După cum am prezentat și mai sus, tehnologia această este implementată în diverse aplicații, cu
ajutorul dispozitivelor de tip Java Application Control Engine (JACE), așa că scopul meu ar putea
fi să achizitionez un astfel de dispozitiv, pentru a mă familiariza mai mult cu acest domeniu.
Având în vedere tendința din ultimii ani, putem trage concluzia că o tehnologie similară va fi
implementată și pentru controlul automobilelor autonome/infrastructura necesară utilizării unor
astfel de mașini, deoarece tendința este ca pe viitor, un server să dețină informații cât și să seteze
viteza autoturismelor ce nu vor avea nevoie de șofer. [10]
Indiferent de cum vor evolua lucrurile, subiectul acestei lucrări, sau mai ales, tehnologia folosită
în conceperea acestei aplicații, client/server, va fi mereu de interes în societatea actuală.
5. Bibliografie
[1] Alex Ciutacu, “Robotii vor lasa oamenii fara locuri de munca” https://www.zf.ro/business-
international/robotii-vor-lasa-800-de-milioane-de-oameni-fara-loc-de-munca-pana-in-2030-iar-
problema-va-fi-mai-grava-in-cadrul-tarilor-bogate-care-sunt-primele-meserii-care-vor-fi-
afectate-16842078
ServerMain
package main.java.com.muc;
server.start();
ServerWorker
package main.java.com.muc;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
import java.net.Socket;
import java.sql.SQLOutput;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
this.server = server;
this.clientSocket = clientSocket;
@Override
try {
handleClientSocket();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
this.outputStream = clientSocket.getOutputStream();
String line;
if ("logoff".equals(cmd) || "quit".equalsIgnoreCase(cmd)) {
handleLogoff();
break;
} else if ("login".equalsIgnoreCase(cmd)) {
handleLogin(outputStream, tokens);
} else if ("msg".equalsIgnoreCase(cmd)) {
handleMessage(tokensMsg);
} else if ("join".equalsIgnoreCase(cmd)) {
handleJoin(tokens);
} else if ("leave".equalsIgnoreCase(cmd)) {
handleLeave(tokens);
} else {
outputStream.write(msg.getBytes());
clientSocket.close();
if (tokens.length > 1) {
topicSet.remove(topic);
}
public boolean isMemberOfTopic(String topic) {
return topicSet.contains(topic);
if (tokens.length > 1) {
topicSet.add(topic);
if (isTopic) {
if (worker.isMemberOfTopic(sendTo)) {
String outMsg = "msg " + sendTo + ": " + login + ": " + body + "\n";
worker.send(outMsg);
} else {
if (sendTo.equalsIgnoreCase(worker.getLogin())) {
worker.send(outMsg);
server.removeWorker(this);
if (!login.equals(worker.getLogin())) {
worker.send(onlineMsg);
}
}
clientSocket.close();
return login;
if (tokens.length == 3) {
outputStream.write(msg.getBytes());
this.login = login;
if (worker.getLogin() != null) {
if (!login.equals(worker.getLogin())) {
send(msg2);
if (!login.equals(worker.getLogin())) {
worker.send(onlineMsg);
} else {
outputStream.write(msg.getBytes());
}
}
if (login != null) {
outputStream.write(msg.getBytes());
Server
package main.java.com.muc;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
this.serverPort = serverPort;
return workerList;
@Override
try {
while (true) {
workerList.add(worker);
worker.start();
}
} catch (IOException e) {
e.printStackTrace();
workerList.remove(serverWorker);
ChatClient:
ChatClient
package com.muc;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
this.serverName = serverName;
this.serverPort = serverPort;
client.addUserStatusListener(new UserStatusListener() {
@Override
}
@Override
});
client.addMessageListener(new MessageListener() {
@Override
System.out.println("You got a message from: " + fromLogin + " ==> " + msgBody);
});
if (!client.connect()) {
System.err.println("Connect failed!");
} else {
System.out.println("Connect successful!");
if (client.login("guest", "guest")) {
System.out.println("Login successful");
System.err.println("Login failed");
//client.logoff();
serverOut.write(cmd.getBytes());
serverOut.write(cmd.getBytes());
if ("ok login".equalsIgnoreCase(response)) {
startMessageReader();
return true;
} else {
return false;
serverOut.write(cmd.getBytes());
@Override
readMessageLoop();
};
t.start();
try {
String line;
if ("online".equalsIgnoreCase(cmd)) {
handleOnline(tokens);
} else if ("offline".equalsIgnoreCase(cmd)) {
handleOffline(tokens);
} else if ("msg".equalsIgnoreCase(cmd)) {
handleMessage(tokensMsg);
ex.printStackTrace();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
listener.onMessage(login, msgBody);
listener.offline(login);
listener.online(login);
}
try {
this.serverOut = socket.getOutputStream();
this.serverIn = socket.getInputStream();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
userStatusListeners.add(listener);
userStatusListeners.remove(listener);
}
messageListeners.add(listener);
messageListeners.remove(listener);
UserListPane
package com.muc;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
this.client = client;
this.client.addUserStatusListener(this);
setLayout(new BorderLayout());
userListUI.addMouseListener(new MouseAdapter() {
@Override
if (e.getClickCount() > 1) {
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setSize(500,500);
f.getContentPane().add(messagePane, BorderLayout.CENTER);
f.setVisible(true);
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 600);
frame.getContentPane().add(userListPane, BorderLayout.CENTER);
frame.setVisible(true);
if (client.connect()) {
try {
client.login("guest", "guest");
} catch (IOException e) {
e.printStackTrace();
@Override
userListModel.addElement(login);
@Override
userListModel.removeElement(login);
MessageListener
package com.muc;
}
UserStatusListener
package com.muc;
MessagePane
package com.muc;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
this.client = client;
this.login = login;
client.addMessageListener(this);
setLayout(new BorderLayout());
add(inputField, BorderLayout.SOUTH);
inputField.addActionListener(new ActionListener() {
@Override
try {
client.msg(login, text);
listModel.addElement("You: " + text);
inputField.setText("");
ex.printStackTrace();
});
@Override
if (login.equalsIgnoreCase(fromLogin)) {
listModel.addElement(line);
LoginWindow
package com.muc;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
public LoginWindow() {
super("Login");
client.connect();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p.add(passwordField);
p.add(loginButton);
loginButton.addActionListener(new ActionListener() {
@Override
doLogin();
});
getContentPane().add(p, BorderLayout.CENTER);
pack();
setVisible(true);
try {
if (client.login(login, password)) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 600);
frame.getContentPane().add(userListPane, BorderLayout.CENTER);
frame.setVisible(true);
setVisible(false);
} else {
} catch (IOException e) {
e.printStackTrace();
loginWin.setVisible(true);
}