UNIVERSITATEA DIN CRAIOVA FACULTATEA DE MATEMATICĂ ŞI INFORMATICĂ SPECIALIZAREA INFORMATICĂ
LUCRARE DE LICENŢĂ
Coordonator Ştiinţific : Asist.univ.dr. Claudiu-Ionuţ Popîrlan
Absolvent: Grosu Mihai Constantin
CRAIOVA - 2010-
1
UNIVERSITATEA DIN CRAIOVA FACULTATEA DE MATEMATICĂ ŞI INFORMATICĂ SPECIALIZAREA INFORMATICĂ
Aplicatii JAVA Client-Server BattleShip
Coordonator Ştiinţific : Asist.univ.dr. Claudiu- Ionuţ Popîrlan
Absolvent: Grosu Mihai Constantin CRAIOVA - 2010-
2
CUPRINS CAPITOLUL 1 INTRODUCERE..............................................................................................4 Notiuni introductive Jocuri.....................................................................................................4 Obiective.................................................................................................................................6 CAPITOLUL 2: GENERALITATI............................................................................................8 2.1. Introducere in limbajul de programare Java....................................................................8 2.3.Elemente Java folosite in dezvoltarea aplicatiei ............................................................13 2.3.1.Java Sockets.........................................................................................................13 ..........................................................................................................................................23 2.3.2. Java Thread..........................................................................................................23 2.3.3. Desenarea in Java.................................................................................................30 2.3.4.Java Swing............................................................................................................35 CAPITOLUL 3:PREGĂTIREA MEDIULUI DE LUCRU......................................................37 3.1. Instalare NetBeans.........................................................................................................37 3.2. Configurare client-server...............................................................................................39 ..................................................................................................................................................39 CAPITOLUL 4:DESCRIEREA APLICATIEI.........................................................................40 4.1. Introducere.....................................................................................................................40 4.2.Structura aplicatiei..........................................................................................................41 4.3. Simularea jocului...........................................................................................................53 CAPITOLUL 5: CONCLUZII..................................................................................................61 BIBLIOGRAFIE.......................................................................................................................62
3
CAPITOLUL 1 INTRODUCERE Notiuni introductive Jocuri Un joc este o activitate recreaţională în care sunt implicaţi unul sau mai mulţi jucători, fiind definit printr-un scop pe care jucătorii încearcă să-l atingă şi un set de reguli care determină ce pot face jucătorii. Jocurile pot implica un singur jucător, dar mai des implică o competiţie între doi sau mai mulţi jucători. Cât timp respectă regulile, de obicei sunt mai multe alegeri pe care jucătorul le poate face. Nerespectarea regulilor se numeşte trişare. În cadrul întregii istorii umane, oamenii au jucat jocuri ca o sursă de divertisment pentru ei înşişi şi pentru alţii şi există o varietate enormă de jocuri. Un joc video este un joc electronic în care se interacţionează cu o interfaţă grafică pentru a genera răspuns vizual pe un ecran. Jocurile video în general au un sistem de recompensare a utilizatorului, de obicei se ţine scorul, acest sistem depinzând de îndeplinirea unor anumite obiective în joc. Termenul joc pe calculator sau "joc pe PC" se referă la un joc care este jucat pe un PC, unde monitorul este principalul mijloc de feedback şi care foloseşte dispozitiv de control un periferic de intrare, de obicei butonarea unui joystick (jocuri din arcade-uri), o combinaţie tastatură & maus/trackball sau un controller, ori o combinaţie dintre cele de mai sus Jocurile pentru computer constituie o categorie de aplicaţii software care este destinată distracţiei. De la apariţia acestora, în lumea computerelor, în anii 1970, până astăzi, industria a evoluat, astfel că putem vorbi cu uşurinţă de multe evenimente de prezentare a jocurilor, cum ar fi E3 sau CeBit la nivel mondial sau CERF în România, precum şi de câteva organizaţii de jucători profesionişti. Există mai multe tipuri de jocuri pe calculator: •
RTS (Real Time Strategy - Strategie în timp real)
•
RTT (Real Time Tactics)
•
RPG (Role Playing Game)
•
TBS (Turn Based Strategy)
•
Simulatoare
•
Action
•
Adventure (aventură)
•
FPS (First Person Shooter) 4
•
TPS (Third Person Shooter)
•
MMO (Massive Multiplayer Online Game)
•
Arcade
•
Board/Card Games (Joc de cărţi sau masă)
La unele tipuri de jocuri se poate adăuga prefixul "MMO", care înseamnă "Massively Multiplayer Online", reprezentând un joc care se poate juca numai online, in care sute de mii de jucatori joaca in acelasi timp, in aceeasi lume. Cele mai multe MMO-uri sunt MMORPGuri. •
Railroad Tycoon II
•
Call of Duty
•
Cossaks - The art of war
•
Starcraft
•
Tomb Raider
•
Hitman
•
Hattrick
•
Midnight Club II
•
Need for Speed
•
Broken Sword
Câteva exemple de jocuri strategice sunt: •
Age of Empires I
•
Age of Empires II
•
Age of Empires III
•
Age of Mythology
•
Age of Wonders
•
Caesar III
•
Caesar IV
•
Children of the Nile
•
Civilization IV
•
Empire Earth
•
Empire Earth 2
•
Empire Earth 3
5
•
Pharaoh
•
Rome Total War
•
Rise of Nation
•
Stronghold
•
Stronghold Crusader
•
Stronghold 2
•
Stronghold Legends
•
World of Warcraft
•
Zeus-Master of Olympus Deși
calculatoarele
personale
au
devenit
populare
o
data
cu
dezvoltarea
microprocesoarelor și minicalculatoarelor, jocurile pe calculator au existat încă de la 1960. Unul dintre primele jocuri pe computer a fost Spacewar dezvoltat in 1961 de către studenții MIT Martin Graetz,Alan Kotok, si Steve Russell. Jocul a fost dezvoltat pe un computer PDP-1, folosit pentru calcule statistice. Prima generatie de jocuri pentru PC a fost „text adventure” sau „interactive fiction”, în care jucătorul comunica cu calculatorul prin introducere anumitor comenzi de la tastatură. Primul text- adventure „Aventura”a fost realizat pentru PDP-11 de Will Crowther în 1976 si a fost dezvoltat de Don Woods in 1977. Prin anii 1980 calculatoarele personale au devenit suficient de putennice pentru a rula jocuri precum Adventura, în acest timp grafica începaând sa devina un factor important în jocuri. O data cu dezvoltarea internetului la scară foarte largă a crescut și piața jocurilor online si client-server: Counter Strike,Dota, Street Fighter Alpha 2, FIFA etc. Jocurile multyplayer sunt mai atractive si acum reprezintă viitorul jocurilor PC deoarece pot userii pot jucua cu adversari umani ceea ce face aceste jocuri din ce in ce mai atractive pentru toate categoriile de varsta. De asemenea aceste jocuri sunt și un mod de a cunoaște oameni din diferite zone șisunt un mod de relaxare de asemenea.
Obiective • Realizarea unei aplicații client-server in Java • Exemplificarea modului de lucru cu soket-uri și thread-uri • Folosirea limbajului de programare Java pentru a creea o aplicație stabilă și ușor de folosit 6
• Importanța Internetului realizarea aplicațiilor bazate pe arhitectura client-server
7
CAPITOLUL 2: GENERALITATI 2.1. Introducere in limbajul de programare Java 1. Ce este JAVA ?
este un limbaj de programare dezvoltat de JavaSoft, companie în cadrul firmei Sun Microsystems.
este complet orientat pe obiecte și oferă posibilitatea reala de refolosire a codului (care este de fapt promisiunea facută la apariția programării orientate pe obiecte).
este neutru din punct de vedere arhitectural, cu alte cuvinte Java este un limbaj independent de platforma de lucru, aceeași aplicație rulând, fără nici o modificare, pe sisteme diferite cum ar fi Windows, UNIX sau Macintosh, lucru care aduce economii substanțiale firmelor care dezvoltă aplicații pentru Internet.
limbajul Java este modelat după C si C++, trecerea de la C, C++ la Java făcându-se foarte usor.
elimină sursele frecvente de erori ce apar în programare prin eliminarea pointerilor, administrarea automata a memoriei si eliminarea fisurilor de memorie printr-o procedură de colectare a “gunoiului” care rulează în fundal;
este cel mai sigur limbaj de programare disponibil în acest moment, asigurând mecanisme stricte de securitate a programelor concretizate prin: verificarea dinamică a codului pentru detectarea secvențelor periculoase, impunerea unor reguli stricte pentru rularea programelor lansate pe calculatoare aflate la distanta (acestea nu au acces la rețeaua locală, la fișierele stocate în sistemul local și nu pot lansa în executie programe locale), etc.
permite creearea unor documente Web îmbunătățite cu animație si multimedia. a fost proiectat pentru a fi folosit în medii distribuite si sisteme deschise. 2.
Evolutia limbajului JAVA
8
In 1991, firma SUN, mergând pe direcția dezvoltării sistemelor deschise de lucru în rețea, a creat un proiect de lucru numit Green, care avea drept scop punerea la punct a unor procesoare care să poată rula pe diferite tipuri de aparate si punerea la punct a unui sistem care sa poata rula pe platforme diferite. Planul initial prevedea dezvoltarea proiectului în C++, dar au apărut foarte multe probleme în încercarea de dezvoltare acompilatorului de C++. Ca urmare, James Gosling, membru al grupului Green, a început să lucreze la dezvoltarea unui nou limbaj, numit Oak, care, mai târziu, avea să se numească Java. De asemenea grupul Green avea sa-si schimbe numele întâi în FirstPerson, apoi în JavaSoft. Abia dupa ce a fost înființata compania Netscape Communications Corporation, cei de la JavaSoft s-au orientat către Internet si Web, mediul multiplatforma distribuit al retelei Internet fiind perfect pentru testarea proiectului. In prezent licența pentru tehnologia Java a fost acordată unor firme precum IBM, Microsoft, Sillicon Graphics, Adobe si Netscape.
3.
Java : un limbaj compilat si interpretat
In funcție de modul de execuție al programelor, limbajele de programare se împart în două categorii :
• interpretate : instructiunile sunt citite linie cu linie de un program numit interpretor si traduse în instrucțiuni masină; avantaj : simplitate; dezavantaje : viteza de execuție redusa
• compilate : codul sursa al programelor este transformat de compilator într-un cod ce poate fi executat direct de procesor; avantaj : executie rapida; dezavantaj : lipsa portabilitatii, codul compilat într-un format de nivel scazut nu poate fi rulat decât pe platforma pe care a fost compilat. Programele Java pot fi atât interpretate cât si compilate. Cod sursa Java →(compilare)→ Cod de octeti Codul de octeti este diferit de codul masină. Codul masină este reprezentat de o succesiune de 0 si 1; codurile de octeti sunt seturi de instrucțiuni care seamănă cu codul scris în limbaj de asamblare. Codul mașină este executat direct de către procesor și poate fi folosit numai pe platforma pe care a fost creat; codul de octeti este interpretat de mediul Java și de aceea poate fi rulat pe orice platforma care foloseste mediul de execuție Java → neutralitatea limbajului Java din punct de vedere arhitectural. 9
Cum este rulat un program Java ? Interpretorul Java transformă codul de octeț într-un set de instrucțiuni masină, întârzierea interpretarii fiind însa foarte mică datorită asemănării dintre codul de octeti si limbajul de asamblare și din acest motiv execuția se face aproape la fel de repede ca în cazul programelor compilate. Cum este obtinută neutralitatea arhitecturala a limbajului Java ? Cu alte cuvinte, cum este posibilă portarea codului de octeti pe calculatoare diferite? Truc : codul sursă este compilat nu pentru calculatorul pe care se lucrează ci pentru un calculator inexistent, acest calculator imaginar fiind numit Masina virtuală Java (Java Virtual Machine). Interpretorul acționează apoi ca un intermediar între Masina virtuala Java si mașina reală pe care este rulat programul.
Aplicatia utilizatorului Obiecte Java Masina virtuala Java UNIX Windows Sisteme de operare
4.
Macintosh
Java si conceptele programarii orientate pe obiecte
Limbajul Java este urmatorul pas logic în domeniul limbajelor de programare și se bazează pe cel mai popular limbaj de programare al momentului C++. In Java se pot obține programe cu aspectul si comportarea programelor C++, dar beneficiind de avantajele oferite de un limbaj proiectat special pentru POO. Java renunță complet la programarea procedurală specifică Cului si va obligă să folosiți conceptele solide ale POO. Conceptele programarii orientate pe obiecte cuprind :
• Obiectele • Încapsularea si transmiterea de mesaje • Clasele • Bibliotecile (numite pachete, în Java) • Moștenirea • Modificatorii de acces Obiectele : 10
unitatea elementara a POO starea obiectului este dată de variabile de instanță comportamentul obiectului este dat metode ușor de refolosit, actualizat, întretinut Încapsularea si transmiterea de mesaje : Clasele : încapsuleaza obiecte o singură clasă poate fi folosită pentru instantierea mai multor obiecte Pachetele: colectie de clase înrudite Mostenirea : permite extinderea functionalitatii unor clase existente refolosirea codului Modificatorii de acces : controlează accesul la metodele si variabilele obiectelor. Acestea pot fi :
1. Private
- accesibile doar obiectelor din aceeasi clasă
2. Protejate - accesibile obiectelor din aceeasi clasă si din subclasele clasei respective
3. Prietenosase - (nivelul de accesibilitate prestabilit) accesibile tuturor claselor din pachetul curent
4. Publice
- accesibile tuturor claselor din orice pachet
Programarea în limbajul Java 5. Caracteristicile de baza al limbajului Java
A.
Folosirea în medii de rețea distribuite
Java a fost proiectat pentru un mediu complex cum este Internetul si de aceea trebuie să poată rula pe platforme eterogene distribuite. Acest lucru este posibil deoarece :
• este neutru din punct de vedere arhiectural = programele pot fi rulate pe orice platformă care are instalat mediul Java
• are un grad ridicat de portabilitate = contine obictecte care pot fi folosite pe platforme eterogene si respectă standardele IEEE (Institue of Electrical and Electronics Engineers) pentru structurile de date (folosirea întregilor, a numerelor în virgulă mobilă, a șirurilor, etc) 11
• este distribuit = poate folosi atât obiecte memorate local cât si obiecte stocate pe calculatoare aflate la distantă
• este compatibil cu mediile de lucru în rețea (poate fi utilizat în rețele complexe) și acceptă direct protocoalele de rețea obisnuite cum ar fi FTP si HTTP
B.
Asigurarea performanței ridicate
• compilatorul si sistemul de executie oferă o viteza ridicată rularii programelor • are încorporate posibilități de execuție multifilară (rularea simultană a mai multor procese) folosind un sistem de acordare de prioritați proceselor ce trebuie executate. Printre procesele care rulează în fundal sunt cele de “colectare a gunoiului” si de gestionare a memoriei.
C.
Refolosirea codului si fiabilitatea
• Java este un limbaj dinamic, lucru asigurat prin întârzierea legării obiectelor și legarea dinamică a claselor în timpul execuției, ceea ce împiedică apariția erorilor în cazul schimbării mediului de lucru dupa compilarea programului sursă.
• Fiabilitatea este asigurata prin eliminarea pointerilor, prin folosirea verificării dinamice a limitelor și prin gestionarea automată a memoriei, înlaturându-se posibilitatea fisurilor și violărilor de memorie. O altă cale de evitare a erorilor este verificarea structurilor de date atât la compilare cât si în timpul executiei.
D.
Asigurarea securitatii
• Interzice accesul la stiva sistemului, la zona libera de memorie si la sectiunile protejate de memorie
• Verifica validitatea codului semnalând urmatoarele: Violările de acces Conversiile ilegale de date Valori si parametri incorecți Modificarea claselor sau folosirea incorectă a acestora Depășirea stivei în partea superioară sau inferioară Activităti suspecte sau neautorizate
12
2.3.Elemente Java folosite in dezvoltarea aplicatiei 2.3.1.Java Sockets O reţea este formată dintr-o mulţime de calculatoare şi periferice (imprimante, plotere, scannere, modemuri etc.) conectate între ele. Un sistem distribuit este o colecţie de calculatoare şi/sau procesoare autonome (având o unitate de comandă proprie), interconectate (capabile de a schimba informaţii între ele). Elementele colecţiei poartă numele de noduri. Un astfel de sistem poate fi programat pentru a rezolva probleme de concurenţă şi de paralelism. Sistemele distribuite au apărut ca o necesitate pentru: - schimbul de informaţii între noduri; - partajarea unor resurse (printere, memorie backup, unităţi de disc etc.); - siguranţa în funcţionare: dacă un nod "cade", întregul sistem trebuie (dacă este posibil) să fie capabil să asigure în continuare funcţionarea, prin redirijarea (rutarea) mesajelor prin nodurile funcţionale. Tipuri de reţele O primă clasificare a reţelelor este constituită de împărţirea lor în reţele LAN (Local Area Network) şi reţele WAN (Wide Area Network). Reţelele LAN sunt folosite de obicei pentru a partaja resurse (fişiere şi periferice) şi de a facilita schimbul de informaţii între nodurile componente. Conectarea tipică este realizată prin cablu, cu o limită dată pentru un drum între două noduri (de exemplu 10 km). La fiecare moment de timp, într-o astfel de reţea este transmis un singur mesaj. Numele reţelei desemnează produsul şi nu reţeaua (aşa cum se întâmplă la reţelele WAN). De exemplu Ethernet este un produs al companiei XEROX. Probleme algoritmice pentru astfel de reţele: 1) sincronizarea: aşteptarea îndeplinirii unei condiţii; 2) difuzarea totală (broadcasting) : transmiterea unui mesaj către toate celelalte noduri; 3) selectarea unui proces pentru îndeplinirea anumitor acţiuni;
13
4) detectarea terminării: un nod ce întreprinde o acţiune, în care antrenează şi alte noduri, trebuie să fie capabil să detecteze momentul încheierii acţiunii; 5) excluderea reciprocă: utilizarea unor resurse sub excludere reciprocă (de exemplu modificarea unui fişier sau scrierea la imprimantă); 6) detectarea şi prevenirea blocării totale (deadlock); 7) gestionarea distribuită a fişierelor. Reţelele WAN permit comunicarea pe distanţe mai mari, prin legături directe între noduri, realizate prin linie telefonică, fibră optică, legătură via satelit etc. Ele sunt grafuri orientate. Probleme algoritmice pentru astfel de reţele: 1) siguranţa schimbului de informaţii pe fiecare arc al grafului. Informaţia eronată trebuie recunoscută ca atare şi corectată. Menţionăm că este posibil ca mesajele să sosească într-un nod în altă ordine decât cea în care au fost transmise, pot fi duplicate etc.; 2) selectarea de căi de comunicare (rutare) între nodurile care schimbă informaţii, deoarece un graf complet este prea costisitor şi în general nici nu este realizabil. Modul de rutare trebuie actualizat în cazul în care un nod al reţelei cade (devine nefuncţional); 3) evitarea congestionării unor căi de comunicaţie, realizată tot prin (re)rutare; 4) evitarea blocării totale; 5) securizarea datelor şi a transmisiilor. Deosebirile esenţiale între cele două tipuri de reţele se referă la: 1) securizare: în reţele LAN se presupune că transmiterea este corectă, pe când în reţelele WAN trebuie presupus că în timpul transmiterii mesajelor se poate întâmpla "ceva rău"; 2) timpul de comunicare: în reţelele WAN timpul de comunicare este mult mai mare (de 10k ori mai mare, k ≥ 1) decât în reţelele LAN; aceast timp este la rândul său mult mai mare decât cel cerut de prelucrările locale; 3) omogeneitatea: în reţelele WAN trebuie presupus că sunt utilizate simultan mai multe protocoale (vezi paragraful următor), ceea ce pune problema recunoaşterii şi conversiei între ele; 4) încrederea reciprocă: nu este presupusă în reţelele WAN şi drept urmare trebuie luate măsuri de securitate adecvate. Protocoale Comunicarea între componentele unei reţele (respectiv unui sistem distribuit) se face prin mulţimi de reguli, numite generic protocoale. 14
Un protocol cuprinde atât formatul mesajului ce este efectiv transmis, cât şi modul în care trebuie răspuns la mesajul respectiv. Protocolul folosit pe Internet este IP (Internet Protocol). Mesajele circulă în pachete, ce pot fi: - pachete Internet, pentru care protocolul este TCP (Transmission Control Protocol); - datagrame, pentru care protocolul este UDP (User Datagram Protocol); nu vom vorbi despre ele. Internetul foloseşte nume (adrese) simbolice pentru reţele şi pentru maşinile gazdă; ele se mai numesc nume de domeniu. Lor li se asociază în mod biunivoc adrese (numerice) IP, folosite efectiv la comunicarea între nodurile reţelei. Asocierea cade în sarcina unui sistem de nume de domeniu (DNS = Domain Name System). O adresă numerică IP are foma: a.b.c.d unde a, b, c, d sunt numere naturale din mulţimea {0, 1, ..., 255}. Modelul Client/Server După cum ştim, comunicarea între nodurile unei reţele constă în transmiterea (recepţionarea) de pachete către (de la) gazde ale aceleaşi reţele sau ale unei alte reţele. Modelul utilizat pe scară largă în sistemele distribuite (şi care va fi cel folosit în continuare) este sistemul Client/Server. În acest model există: - o mulţime de procese Server, fiecare jucând rolul de gestionar de resurse pentru o colecţie de resurse de un anumit tip; - o mulţime de procese Client; fiecare execută activităţi care necesită acces la resurse hard/soft disponibile (partajate) de servere. Un gestionar de resurse poate avea şi el nevoie de resurse gestionate de un alt proces Server. Drept urmare, unele procese pot fi atât de tip Client, cât şi de tip Server. Dar doar serverele gestionează resurse. Serverele sunt cele care îşi încep primele activitatea. În mod tipic, un server oferă succesiv clienţilor posibilitatea de a se conecta la el (spunem că acceptă conexiuni de la clienţi). La început clientul îşi manifestă dorinţa de a se conecta şi, dacă serverul este gata să accepte conexiunea, aceasta se realizează efectiv; este vorba deci de o acţiune de la client către server. Apoi transmisia informaţiilor devine bidirecţională, fluxul de informaţii putând circula acum în ambele sensuri. 15
Teoretic, activitatea unui server se desfăşoară la infinit. Pentru conectare la server, clientul trebuie să cunoască adresa serverului (fie cea numerică, fie cea simbolică), precum şi numele portului pus la dispoziţie de server. Portul nu este o locaţie fizică, ci o extensie software corespunzătoare unui serviciu. Serverul poate oferi mai multe servicii, pentru fiecare existând un număr de port. Cel standard sunt: 7 : ping (ecou)
21 : ftp (transfer de fişiere)
23 : telnet
25 : email
79 : finger
80 : Web
110 : POP3 (Post Office Protocol) Porturile din intervalul 0..1023 sunt în general rezervate pentru servicii speciale (de genul celor de mai sus) şi pentru clienţi privilegiaţi. Clientul iniţiază conexiunea prin reţea, specificând adresa serverului şi portul prin care doreşte să comunice. Serverul trebuie să precizeze numai portul; apoi el trebuie să execute o comandă prin care să anunţe că este gata să accepte conexiuni pe portul respectiv; drept urmare el rămâne în aşteptare până când un client doreşte să se conecteze şi conexiunea este stabilită cu succes. Un server poate accepta conexiuni de la mai mulţi clienţi: pentru fiecare crează un fir de executare. Clasa InetAddress Această clasă, aflată în pachetul java.net, furnizează informaţii asupra adreselor (simbolică şi numerică) unui calculator gazdă. Clasa nu are constructori publici. Principalele metode sunt: public static InetAddress getLocalHost() returnează numele calculatorului gazdă (pe care se află în curs de executare aplicaţia). Acest nume, convertit la String, are forma: adresă_simbolică/adresă_IP; public static InetAddress getByName(String s) dându-se ca argument adresa simbolică sau numerică a calculatorului gazdă, metoda întoarce un obiect de tipul InetAddress; metoda poate lansa excepţia UnknownHostException; public String getHostName() întoarce adresa simbolică a calculatorului gazdă; public byte[] getAddress() întoarce un tablou de 4 octeţi, ce compun adresa numerică. Exemplul 1. Determinarea adreselor unui calculator şi obţinerea uneia dintre aceste adrese cunoscând-o pe cealaltă:
16
import java.net.*; class Adrese { public static void main(String[] sss) throws Exception { InetAddress gazda = null; gazda = InetAddress.getLocalHost(); System.out.println(gazda.toString()); } }
Întrebare. "Are sens să studiem facilităţile oferite de Java pentru lucru în reţea dacă avem la dispoziţie un singur calculator?". DA! Putem de exemplu deschide mai multe ferestre de comandă. Adresa IP: numele calculatorului, numele standard "localhost" sau "127.0.0.1". Comunicare prin socket-uri Socket-urile sunt folosite pentru transmiterea de date folosind protocolul TCP/IP. Ele sunt obiecte ce trebuie create la ambele capete ale conexiunii. Socket-urile client sunt obiecte de tipul clasei Socket, iar socket-urile server sunt obiecte de tipul clasei ServerSocket; ambele clase fac parte din pachetul java.net. Socket-urilor li se pot ataşa un flux de intrare şi unul de ieşire, prin care pot recepţiona/ transmite, date. Prezentăm în continuare schema generală a lucrului cu socket-uri, apelând la facilităţile de intrare/ieşire la nivel de octet. Un mod tipic de creare a unui socket client este următorul: try { Socket cs = null; cs = new Socket("adresa",nrport); DataInputStream is = new DataInputStream(cs.getInputStream()); DataOutputStream os = new DataOutputStream(cs.getOutputStream()); } catch(UnknownHostException e) { ... } catch(IOException e) { ... }
17
unde adresa este adresa IP a serverului, iar nrport este numărul portului ales pentru comunicare. Socket-ului îi sunt ataşate fluxul os ce va fi folosit pentru a transmite date serverului, precum şi fluxul is ce va fi folosit pentru recepţionarea datelor transmise de server. Un mod tipic de creare a unui socket server este următorul: ServerSocket ss = null; Socket cs = null; try { ss = new ServerSocket(nrport); // System.out.println("Serverul a pornit"); } catch(IOException e) { ... } try { cs = ss.accept(); DataInputStream is = new DataInputStream(cs.getInputStream()); DataOutputStream os = new DataOutputStream(cs.getOutputStream()); } catch(UnknownHostException e) { ... } catch IOException e) { ... }
Observăm că pentru server nu este necesară precizarea unei adrese IP, ci numai a unui port, care trebuie să coincidă cu cel folosit de client. Metoda accept: se aşteptă ca un client să încerce să se lege la server; în momentul în care acest lucru se întâmplă şi legătura s-a stabilit, metoda creează şi întoarce un socket cs de tip client. Acestuia îi ataşăm un flux de intrare şi unul de ieşire.
Clie nt
cs
Serv er
os
is
is
os
cs
18
ss
În final toate socket-urile şi fluxurile trebuie închise explicit prin invocarea metodei close. . •
Clasa URL
Clasa URL este declarată în pachetul java.net prin: public final class URL extends Object implements Serializable Un obiect de tip URL, numit şi locaţie URL, este o referinţă la o resursă Web. Resursa poate fi un fişier, un director, dar şi un obiect mai complex ca de exemplu o cerere către o bază de date sau un motor de căutare. Ca sintaxă, o astfel de adresă cuprinde 4 părţi: protocol://
adresa :port
/cale
unde protocol desemnează serviciul exportat de server sau căutat de client (de exemplu http sau ftp), adresa este adresa simbolică sau numerică a maşinii gazdă referite, port portul folosit pentru comunicare, iar cale identifică resursa. Un exemplu este următorul: http://www.ncsa.uiuc.edu:8080/demoweb/url-primer.html Sunt folosite şi locaţii URL parţiale, ce specifică doar unele părţi din forma completă a locaţiei; acest lucru este posibil în situaţiile în care celelalte părţi sunt implicite sau se deduc din context. De exemplu poate lipsi numele maşinii gazdă (dacă facem referire la maşina locală) sau portul (dacă este folosit un port implicit). Constructorul "complet" are forma: public URL(String protocol, String gazda, int port, String fisier) Metode (publice), ale clasei URL : String getPath() întoarce calea din locaţia URL; int getPort() întoarce numărul portului din locaţia URL; String getProtocol() întoarce protocolul din locaţia URL; String getHost() întoarce adresa maşinii gazdă din locaţia URL; String getFile() 19
întoarce numele fişierului din locaţia URL; String toString() întoarce reprezentarea sub formă de şir de caractere a locaţiei URL.
Exemplul 2. Dorim să aflăm dacă un server având o adresă dată oferă sau nu servicii Web. Va fi creat un socket de tip client. Adresa este furnizată în comanda java. // Executarea se face prin: java WebCheck adresa import java.io.*; import java.net.*; public class WebCheck { public static void main(String[] adresa) { Socket web = null; System.out.print("Serverul " + adresa[0]); try { web = new Socket(adresa[0],80); System.out.println(" ofera servicii Web"); web.close(); } catch(IOException e) { System.out.println(" nu ofera servicii Web"); } } }
Exemplul 3. Chat (o conversaţie) între două calculatoare.
20
Pentru simplificare, considerăm că fiecare mesaj trimis de la un calculator la celălalt se reduce la o linie de text. Serverul este primul care trebuie pornit. Apoi clientul este cel care începe discuţia, transmiţând un mesaj şi aşteptând să primească mesajul de răspuns, activităţi care se repetă până când clientul transmite mesajul "STOP". Serverul repetă şi el succesiunea de activităţi recepţie + transmisie până când primeşte mesajul "STOP". Clientul va folosi unitatea de compilare Client.java, iar serverul va folosi unitatea de compilare Server.java.
// Unitatea de compilare Client.java import java.net.*; import java.io.*; class Client { public static void main (String[] sir) throws IOException { Socket cs = null; DataInputStream is=null; DataOutputStream os=null; try { cs = new Socket("localhost",5678); is = new DataInputStream(cs.getInputStream()); os = new DataOutputStream(cs.getOutputStream()); } catch(UnknownHostException e) { System.out.println("Host inexistent"); } DataInputStream stdin = new DataInputStream(System.in); String linie; for( ; ; ) { linie = stdin.readLine()+"\n"; os.writeBytes(linie); System.out.println("Transmisie :\t" + linie); if (linie.equals("STOP\n")) break; linie = is.readLine(); 21
System.out.println("Receptie :\t" + linie); } System.out.println("GATA"); cs.close(); is.close(); os.close(); } }
// Unitatea de compilare Server.java import java.net.*; import java.io.*; class Server { public static void main (String[] sir) throws IOException { ServerSocket ss = null; Socket cs = null; DataInputStream is=null; DataOutputStream os=null; ss = new ServerSocket(5678); System.out.println("Serverul a pornit !"); cs = ss.accept(); is = new DataInputStream(cs.getInputStream()); os = new DataOutputStream(cs.getOutputStream()); DataInputStream stdin = new DataInputStream(System.in); String linie; for( ; ; ) { linie = is.readLine(); System.out.println("Receptie :\t" + linie); if (linie.equals("STOP")) break; linie = stdin.readLine()+"\n"; os.writeBytes(linie); 22
} cs.close(); is.close(); os.close(); } }
2.3.2. Java Thread Un sistem multiprocesor (SM) este un mecanism ce permite unui sistem de a folosi mai mult de un procesor. Sistemul Mutiprocesor Simetric (SMS) este o parte a Calculului Paralel unde toate procesoarele sunt identice. Intr-un SMS, procesoarele sunt dirijate in asa fel încât sarcinile sunt împartite de către sistemul de operare iar aplicațiile sunt executate pe mai multe procesoare ce împart același spatiu de memorie. SMS garantează că întreg numărul de procesoare deservește sistemul de operare. Fiecare sub-proces poate fi executat pe orice procesor liber. Astfel se poate realiza echilibrarea încarcării între procesoare. Java conține câteva caracteristici care-l fac un limbaj ideal pentru SMS. Este un limbaj orientat obiect foarte simplu și este conceput să suporte programarea multiprocesor. Multitasking-ul este o metodă prin intermediul căreia mai multe procese utilizează în comun resursele calculatorului (inclusiv procesorul). În situaţia unui calculator cu un singur procesor, se spune că în orice moment rulează cel mult un proces, ceea ce înseamnă că procesorul execută instrucţiunile unui singur proces la un moment dat. Sarcina alegerii procesului care să se afle în execuţie la un moment dat este o problemă de planificare. Operaţia de a opri un proces aflat în execuţie, pentru a-i aloca un timp procesor altui proces aflat în aşteptare se numeşte schimbare de context (context switch). Realizarea frecventă a acestor schimbări de context crează iluzia excuţiei în paralel a mai multor programe. În cazul unui calculator cu mai multe procesoare, multitasking-ul permite execuţia unui număr de procese mai mare decât numărul de procesoare. Sistemul de operare este cel care se ocupă de planificarea proceselor, planificare ce se încadrează într-una din următoarele strategii: 23
•
în cazul sistemelor cu multiprogramare, procesul current se află în execuţie până în momentul în care realizează o operaţie ce presupune aşteptarea după un eveniment extern (o operaţie de I/O), sau până când planificatorul de procese forţează eliberarea procesorului.
•
într-un sistem de tip time-sharing, fiecare process va elibera procesorul în mod voluntar după expirarea cuantei de timp alocate acestuia sau în urma apariţiei unui eveniment hardware cum ar fi o întrerupere.
•
în cadrul sistemelor real-time, unui proces aflat în stare de aşteptare i se garantează accesul la procesor în cazul apariţiei unui eveniment extern. Astfel de sisteme sunt proiectate pentru controlul unor dispozitive mecanice cum ar fi roboţii industriali.
Comutarea între procese consumă timp procesor pentru ca planificatorul de procese să îngheţe starea unui proces şi să dezgheţe starea altui proces (schimbare de context). Dacă mai multe procese concurente sunt executate pe acelaşi procesor şi toate execută calcule atunci timpul total de execuţie va fi mai mare decât timpul de execuţie al unui program secvenţial echivalent. Creşterea vitezei sistemului se poate realiza prin întreţeserea diferitelor faze ale mai multor procese. În cadrul unui proces se pot identifica două tipuri de faze din punct de vedere logic: faza de calcul şi faza de I/O. Faza de calcul se realizează exclusiv la nivelul procesorului utilizându-se la maxim funcţiunile acestuia. Faza de I/O (intrare/ieşire) presupune un aport mai mare din partea perifericelor (imprimante, hard discuri, plăci de reţea, etc), procesul aşteptând ca un periferic să-şi termine sarcina. În timp ce un proces se află într-o fază de I/O aşteptând după finalizarea unei operaţii de către un dispozitiv periferic, un proces aflat în faza de calcul poate ocupa procesorul. În cazul multitasking-ului preemtiv planificatorul de procese alocă cuante de timp procesor egale fiecărui proces, asigurândule astfel un tratament echitabil. De asemenea, sistemul poate răspunde rapid unui eveniment extern (cum ar fi sosirea unor date) ce presupune procesarea de către procesul curent sau de către un altul. În cazul multitasking-ului non-preemtiv, planificatorul îi dă controlul unui proces până când acesta se termină, sau eliberează singur procesorul. Ce sunt thread-urile? Thread-ul reprezintă execuția liniară a unei singure secvențe de instrucțiuni ce rulează in interiorul programului nostru. Toti programatorii sunt familiarizati cu scrierea programelor secvențiale. Programele secvențiale au un punct de start, o secventa de executie si un punct 24
terminal. Caracteristica cea mai importanta la un program secvential este aceea ca în orice moment se execută o singură instructiune. Thread-ul este similar cu un program secvential: are si el un punct de start, o secventa de execuție si un punct terminal. De asemenea intr-un thread se execută doar o singură instructiune la un moment dat. Si totusi un thread nu este la fel ca un program obisnuit. Spre deosebire de programe, thread-ul nu poate exista de unul singur. Thread-urile coexistă in interiorul unui program. Prin urmare putem avea mai multe thread-uri care se execută simultan.
De ce sa folosim thread-uri? Un singur thread nu oferă nimic nou. Orice program scris pâna acum avea cel putin un thread in interiorul său. Noutatea apare atunci când vrem sa folosim mai multe thread-uri, ceea ce inseamna că aplicația noastră poate să facă mai multe lucruri in acelasi timp. Fiecare thread poate sa facă altceva in acelasi timp: unul sa încarce o pagină Web, altul sa animeze o icoana sau toate pot colabora la acelasi job (generarea unei imagini 3D). Când se folosește corespunzator multithreading-ul performanțele applet-ului sau a aplicației unde este folosit cresc simtitor. Multithreading-ul poate simplifica fazele de proiectare si planificare a tuturor sarcinilor greu de implementat într-un program secvențial. Un exemplu de thread-uri este un procesor de text care poate sa tipărească o pagină (paginare, încadrare si trimitere către imprimantă) in background. Se poate continua editarea în timp ce pagina este trimisă către imprimantă. Alt exemplu este acela a unui browser Web care permite defilarea unui text al unei pagini pe care tocmai ați incarcat-o în timp ce browser-ul se ocupă cu aducerea imaginilor. Thread-urile pot face calculul mai rapid. Prin segmentarea unui task in subtask-uri și apoi având câte un thread pentru fiecare subtask se poate creste mult viteza de execuție. Aceasta afirmatie este general valabila pentru un SMS. Când se executa doua threaduri, ele vor fi executate simultan, fiecare pe câte un procesor și astfel se realizează o creștere semnificativă a vitezei. Avantaje similare se obțin când se utilizează Java pe alte platforme de calcul paralel și distribuit cum ar fi Sistemele cu Memorie Distribuita (SMD). Concurenta thread-urilor.
25
Fară a intra intr-o discutie pe teme hardware, este bine de spus ca procesoarele calculatoarelor pot executa doar o instructiune la un moment dat. De ce spunem ca thread-uri diferite se execută in acelasi timp? Pe o masina multiprocesor, thread-urile pot exista pe procesoare diferite in acelasi timp fizic, aceasta mentinându-se valabil chiar daca procesoarele sunt pe calculatoare diferite conectate într-o rețea. Dar și pe o masină cu un singur procesor, thread-urile pot împărți același procesor, rulând într-o manieră intretesuta, competiția pentru timpii CPU creând iluzia ca ele se execută simultan. Aceasta iluzie pare reală atunci cind, de exemplu, 30 de imagini distincte pe secundă captate de ochiul uman sunt percepute intr-un flux continuu de imagine. Aceasta comutare între thread-uri are si ea un pret. Consumă timp CPU pentru ca acesta să înghețe starea unui thread și să dezghete starea unui alt thread (schimbare de context). Dacă thread-urile concurente sunt executate pe acelasi procesor și toate execută calcule atunci timpul total de execuție nu va lua mai mult decât timpul de execuție al unui program secvential care realizează același lucru. Din moment ce într-un sistem monoprocesor thread-urile concură la timpul procesor cum este posibila cresterea vitezei sistemului? Aceasta se realizează prin intreteserea unor faze diferite ale mai multor thread-uri. Multe task-uri pot fi segmentate logic in tipuri de faze: faza de calcul si faza I/O. Faza de calcul necesita atentia maximă din partea CPU-ului prin utilizarea unor metode de calcul. Faza de I/O (intrare/iesire) necesita atentie maxima din partea perifericelor (imprimante, hard discuri, plăci de retea, etc) și în aceste situații procesorul este în general liber, asteptând ca perifericul să-și termine sarcina. Cresterea vitezei este obtinută prin intreteserea fazelor. In timp ce un thread se află într-o fază de I/O asteptând ca o secvență de date sa fie încarcată de pe hard disk, un thread cu o fază de calcul poate ocupa procesorul și când ajunge la o faza I/O, celălalt thread (care tocmai a terminat faza I/O proprie)poate începe sa utilizeze CPU-ul. Contextul thread-urilor si memoria distribuita Thread-urile rulează în contextul unui program, folosind resursele acestuia. Fiecare thread are propriile variabile și puncte de execuție, dar variabilele globale sunt împărțite de toate thread-urile. Deoarece împart același spațiu (variabilele globale și alte resurse) toate firele de execuție pot accesa la un moment dat aceeasi dată. Pentru un programator într-un sistem cu memorie distribuită, împartirea memoriei este un lucru transparent, realizat la un 26
nivel ascuns al sistemului de operare. Oricum, în cazul unor asemenea sisteme, trebuie avută o atenție sporită pentru minimizarea utilizării concurentă a variabilelor comune de către mai multe thread-uri, deoarece această situație ar putea degenera într-o sufocare a aplicației. Thread-urile Java sunt implementate de clasa Thread, iar actuala implementare a thread-urilor este realizată de catre sistemul de operare. In Java, fiecare thread este încapsulat intr-o clasă și rulează prin intermediul unor metode specifice în instanța unei clase. Aceasta instanță nu este o instanță a clasei Thread ci este o instanță a unei clase derivată din clasa Thread sau a unei clase care implementează interfata Runnable (Runnable Interface). Clasele care instantiază astfel de obiecte sunt numite "runnable classes" și obiectele sunt numite "runnable objects". Executia unui thread începe cu apelarea unei metode din clasa Runnable sau dintr-o subclasa a acesteia. Aceasta metodă se execută atâta timp cât ea există și apoi thread-ul moare (aceasta implică faptul că pentru o metodă ce execută o bucla infinită, thread-ul asociat nu moare niciodata). Un thread poate sa fie terminat drept urmare a unui eveniment extern. Limbajul Java ofera doua căi pentru crearea firelor de executie : •
Crearea unei clase care extinde clasa Thread din biblioteca de clase java.lang
•
Crearea unei clase care implementeaza interfața Runnable din biblioteca de clase java.lang
Clasa Thread de asemenea implementeaza interfata Runnable. class TestThread extends Thread { public void run() { System.out.println ("Hello World!"); } }
Exemplul de clasa derivată din clasa Thread suprascrie una din metodele sale - metoda run(). Metoda run() este cea mai importantă deoarece conține codul pe care thread-ul il va executa. Pentru majoritatea thread-urilor aceasta metodă contine o bucla infinită. Pentru a lansa in executie metoda run() mai întâi trebuie creată o instanță a acestei clase, apoi se apeleză metoda start() ce face thread-ul activ si invoca metoda run().
27
class Test { public static void main(String Args[]) { new TestThread().start(); } }
Secvența de cod anterioară combinată cu clasa TestTread va afișa mesajul "Hello world!" pe ecran. Ce se intampla de fapt aici? Metoda main() va porni thread-ul și se va termina; thread-ul nu se va termina însă în acest moment. El va executa metoda run() până când aceasta se termină. Metoda run() va afisa efectiv mesajul "Hello world!" pe ecran si apoi va iesi. Cand si metoda main() și metoda run() se vor fi terminat, se poate reda controlul sistemului. O alta modalitate de a crea thread-uri este aceea ca o clasă sa implementeze interfața Mai există si alti constructori în clasa Thread, cum ar fi: Thread (ThreadGroup ,Runnable, String). Parametrul ThreadGroup asigneaza thread-ul la un grup de thread-uri multime de thread-uri ce permite tratarea unitara a tuturor thread-urile componente. Parametrul de tip String suporta un nume pentru acest nou thread. Acest nume poate fi folosit impreuna cu metoda getName() a clasei Thread pentru o referire de tip mnemonic a unui thread. Acesti parametrii sunt optionali (de altfel exista 7 tipuri diferite de constructori pentru clasa Thread). Thread-uri daemon Multe sisteme prezinta thread-uri cu scopul de a facilita diverse servicii (servicii de I/O, ascultare pe socket, etc). Aceste thread-uri se afla majoritatea timpului in starea idle si numai cind primesc un mesaj incep sa-si execute sarcina specifica. Aceste thread-uri sunt cunoscute sub numele de "Daemon Threads". Orice thread poate deveni daemon prin apelarea metodei proprii setDaemon() cu valoarea true. Se poate verifica starea unui thread prin intermediul metodei isDaemon(). Starile thread-urilor Creand o instanta a unui thread acesta nu este lansat. Sarcina de a lansa thread-ul in executie este realizata de metoda start(). Un thread se poate gasi in diferite stari in functie de evenimentele petrecute.
28
1. Thread nou creat - Metoda run() nu este in executie, timpul procesor nu este
inca
alocat. Pentru a porni un thread trebuie apelata functia start(). In aceasta stare se poate apela de asemenea metoda stop(), care va distruge thread-ul. 2. Thread in executie - Thread-ul a fost lansat in executie cu metoda start(). Este threadul pe care procesorul il executa in acest moment. 3. Thread gata de executie (runnable) - Thread-ul a fost startat dar nu se afla in executie in acest moment. 4. Motivul ar fi acela ca thread-ul a renuntat la procesor apeland metoda yield(), sau din cauza unui mecanism de programare a timpului procesor care a decis sa distribuie acest timp altui thread. Thread-ul va putea trece in executie cind mecanismul de programare va decide acest lucru. Atita timp cit exista un alt thread cu o prioritate mai mare, thread-ul nu va trece in executie. 5. Thread nepregatit pentru executie (blocked) - Thread-ul nu poate fi executat din anumite motive. Ar putea sa astepte terminarea unei operatii de tip I/O, sau s-a apelat.una din metodele wait(), sleep() sau suspend(). Prioritatile thread-urilor Fiecarui thread ii este atribuita o prioritate cuprinsa intre MIN_PRIORITY (egala cu 1) si MAX_PRIORITY (egala cu 10). Un thread mosteneste prioritatea de la thread-ul care l-a creat, dar aceasta prioritate se poate modifica apelind metoda setPriority(); valoarea acestei prioritati se poateobtine in urma apelului metodei getPriority(). Algoritmul de planificare intodeauna va lansa thread-ul cu prioritatea cea mai mare in executie. Daca exista mai multethread-uri cu aceeasi prioritate maxima atunci procesorul le va executa in maniera round-robin. Astfel un thread cu prioritate mai mica se poate executa numai atunci cind toate thread-urile de prioritate mai mare sunt in starea non-runnable. Prioritatea thread-ului main() este NORM_PRIORITY (egala cu 5). Grupuri de thread-uri Fiecare thread apartine unui grup de thread-uri. Un grup de thread-uri este o multime de thread-uri (si posibil grupuri de thread-uri) impreuna cu un mecanism de realizare a operatiilor asupra tuturor membrilor multimii. Grupul implicit de thread-uri este implicit numit main, si fiecare group de thread-uri nou creat apartine acestui grup, mai putin acelea specificate in constructorul sau. 29
Pentru a afla pentru un thread la ce grup de thread-uri apartine se poate folosi metoda getThreadGroup(). Pentru a crea propriul nostru grup de thread-uri, trebuie mai intii sa cream un obiect ThreadGroup. Se poate folosi unul din acesti constructori: •
ThreadGroup(String) - creaza un nou ThreadGroup cu numele specificat.
•
ThreadGroup(threadGroup, String) - creaza un nou ThreadGroup cu numele specificat si apartinind la un anumit grup de thread-uri.
Dupa cum arata si al doilea constructor, un grup de thread-uri poate fi creat in interiorul altui grup de thread-uri. Cel mai nou grup de thread-uri creat devine membru la cel mai vechi realizindu-se astfel o ierarhie de grupuri. Pentru a crea un thread in interiorul unui grup de thread-uri, altul decit grupul main trebuie doar mentionat numele grupului atunci cind se apeleaza constructorul thread-ului. In momentul in care avem mai multe thread-uri organizate intr-un grup de thread-uri putem apela la operatii comune pentru toti membrii acestui grup. Aceste operatii sunt in principal stop(), supend() and resume() care au aceeasi semnificatie ca atunci cind se foloseste unsingur thread. Pe langa aceste operatii mai exista si alte operatii specifice grupului de thread-uri.
2.3.3. Desenarea in Java In afara posibilității de a utiliza componente grafice standard, Java oferă și posibilitatea de control la nivel de punct (pixel) pe dispozitivul grafic, respectiv desenarea a diferite forme grafice direct pe suprafata unei componente. Desi este posibil, în general nu se deseneaza la nivel de pixel direct pe suprafata ferestrelor. In Java a fost definit un tip special de componenta numita Canvas (pânza de pictor), al carui scop este de a fi extins pentru a implementa componente cu o anumita înfatisare. Asadar clasa Canvas este o clasa generica din care se deriveaza subclase pentru crearea suprafetelor de desenare. Constructorul Canvas() creeaza o plansa, adica o componenta pe care se poate desena. Plansele nu pot contine alte componente grafice, ele fiind utilizate doar ca suprafete de desenat sau ca fundal pentru animatie. Constructor Canvas () Metode addNotify ()
Creates the peer of the canvas.
30
paint(Graphics)
Paints the canvas in the default background color.
Metoda paint() a clasei Canvas() picteaza plansa în culoarea implicita a fundalului. Pentru a redesena plansa cu un alt continut, se recomanda supradefinirea acestei metode implicite. class Tablou extends Canvas { public void paint(Graphics g) { //...desenare continut } }
Toate desenele care trebuie sa apara pe o suprafata de desenare se realizeaza în metoda public void paint(Graphics g), în general apelata intern în urma unui apel repaint(), ori de câte ori componenta respectiva trebuie reafisata. In general desenarea se poate face :
• pe o portiune de ecran, • la imprimanta sau • într-o zona virtuala de memorie Inainte ca utilizatorul sa poata desena el trbuie sa obtina un context de desenare pentru fereastra careia îi apartine regiunea pe care se va desena. Acest context grafic este specificat prin intermediul obiectelor de tip Graphics primite ca parametru în functia paint(). In functie de dispozitivul fizic pe care se face afisarea (ecran, imprimanta, plotter, etc) metodele de desenar au implementari interne diferite, transparente utilizatorului. Asadar, clasa Graphics ofera posibilitatea de a desena linii, forme geometrice, imagini si caractere. Constructor Graphics () Constructs a new Graphics Object. Metode clearRect (int, int, int, int) Clears the specified rectangle by filling it with the current background color of the current drawing surface. clipRect(int, int, int, int) 31
Clips to a rectangle. copyArea(int, int, int, int, int, int) Copies an area of the screen. create() Creates a new Graphics Object that is a copy of the original Graphics Object. create(int, int, int, int) Creates a new Graphics Object with the specified parameters, based on the original Graphics Object. dispose() Disposes of this graphics context. draw3DRect(int, int, int, int, boolean) Draws a highlighted 3-D rectangle. drawArc(int, int, int, int, int, int) Draws an arc bounded by the specified rectangle from startAngle to endAngle. drawBytes(bytest, int, int, int, int) Draws the specified bytes using the current font and color. drawChars(charst, int, int, int, int) Draws the specified characters using the current font and color. drawImage(Image, int, int, ImageObserver) Draws the specified image at the specified coordinate (x, y). drawImage(Image, int, int, int, int, ImageObserver) Draws the specified image inside the specified rectangle. drawImage(Image, int, int, Color, ImageObserver) Draws the specified image at the specified coordinate (x, y), with the given solid background Color. drawImage (Image, int, int, int, int, Color, ImageObserver) Draws the specified image inside the specified rectangle, with the given solid background Color. drawLine(int, int, int, int) Draws a line between the coordinates (x1,y1) and (x2,y2). drawOval(int, int, int, int) Draws an oval inside the specified rectangle using the current color. drawPolygon(intst, intst, int) Draws a polygon defined by an array of x points and y points. 32
drawPolygon(Polygon) Draws a polygon defined by the specified point. drawRect(int, int, int, int) Draws the outline of the specified rectangle using the current color. drawRoundRect(int, int, int, int, int, int) Draws an outlined rounded corner rectangle using the current color. drawString(String, int, int) Draws the specified String using the current font and color. fill3DRect(int, int, int, int, boolean) Paints a highlighted 3-D rectangle using the current color. fillArc(int, int, int, int, int, int) Fills an arc using the current color. fillOval(int, int, int, int) Fills an oval inside the specified rectangle using the current color. fillPolygon(intst, intst, int) Fills a polygon with the current color using an even-odd fill rule (otherwise known as an alternating rule). fillPolygon(Polygon) Fills the specified polygon with the current color using an even-odd fill rule (otherwise known as an alternating rule). fillRect(int, int, int, int) Fills the specified rectangle with the current color. fillRoundRect(int, int, int, int, int, int) Draws a rounded rectangle filled in with the current color. finalize() Disposes of this graphics context once it is no longer referenced. getClipRect() Returns the bounding rectangle of the current clipping area. getColor() Gets the current color. getFont() Gets the current font. getFontMetrics() Gets the current font metrics. 33
getFontMetrics(Font) Gets the current font metrics for the specified font. setColor(Color) Sets the current color to the specified color. setFont(Font) Sets the font for all subsequent text-drawing operations. setPaintMode() Sets the paint mode to overwrite the destination with the current color. setXORMode(Color) Sets the paint mode to alternate between the current color and the new specified color. toString() Returns a String object representing this Graphic's value. translate(int, int) Translates the specified parameters into the origin of the graphics context. Prin dreptunghi de decupare (clip area) se întelege zona din suprafata componentei de afisare în care sunt vizibile operatiile efectuate. Orice operatie efectuata în afara acestui dreptunghi nu are nici un efect. Stabilirea unui dreptunghi de decupare se realizeaza prin : clipRect(int x, int y, int width, int height) Proprietatile contextului grafic
• culoarea de desenare Color getColor() void setColor(Color)
• originea coordonatelor - poate fi modificata prin : translate(int x, int y)
• modul de desenare void setXorMode() - scriere “sau exclusiv” (culoare + fundal = culoare, culoare + culoare = fundal, (culoare + culoare1) + culoare = culoare1 ) void setPaintMode() - suprascriere
• fontul curent pentru desenarea caracterelor Font getFont() 34
void setFont(Font)
• zona de decupare (în care sunt vizibile modificarile) Shape getClip() void setClip(Shape) void setClip(int x, int y, int w, int h) In Swing, pentru a eficientiza desenarea, obiectul de tip Graphics primit ca argument de metoda paintComponent este refolosit pentru desenarea componentei, a chenarelor ¸si a fiilor sai. Din acest motiv este foarte important ca atunci cand supradefinim metoda paintComponent sa ne asiguram ca la terminarea metodei starea obiectului Graphics este aceea¸si ca la inceput. Acest lucru poate fi realizat fie explicit, fie folosind o copie a contextului grafic primit ca argument: // 1.Explicit Graphics2D g2d = (Graphics2D)g; g2d.translate(x, y); // modificam contexul ... g2d.translate(-x, -y); // revenim la starea initiala
// 2. Folosirea unei copii Graphics2D g2d = (Graphics2D)g.create(); g2d.translate(x, y); ... g2d.dispose();
2.3.4.Java Swing Tehnologia Swing face parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) care pune la dispozitie o serie intreaga de facilitati pentru scrierea de aplicatii cu o interfata grafica mult imbogatita functional si 35
estetic fata de vechiul model AWT. In JFC sunt incluse urmatoarele: •
Componente Swing Sunt componente ce inlocuiesc si in acelasi timp extind vechiul set oferit de modelul AWT.
•
Look-and-Feel Permite schimbarea iınfatisarii si a modului de interactiune cu aplicatiain functie de preferintele fiecaruia. Acelasi program poate utiliza diversemoduri Look-andFeel, cum ar fi cele standard Windows, Mac,Java, Motif sau altele oferite de driver si dezvoltatori, acestea putand fiinterschimbate de catre utilizator chiar la momentul executiei .
•
Accessibility API Permite dezvoltarea de aplicatii care sa comunice cu dispozitive utilizatede catre persoane cu diverse tipuri de handicap, cum ar fi cititoarede ecran, dispozitive de recunoastere a vocii, ecrane Braille, etc.
•
Java 2D API Folosind Java 2D pot fi create aplicatii care utilizeaza grafica la unnivel avansat. Clasele puse la dispozitie permit crearea de desene complexe,efectuarea de operatii geometrice (rotiri, scalari, translatii, etc.),prelucrarea de imagini, tiparire, etc.
•
Drag-and-Drop Ofera posibilitatea de a efectua operatii drag-and-drop intre aplicatiiJava si aplicatii native.
•
Internationalizare Internationalizarea si localizarea aplicat¸iilor sunt doua facilitati extremde importante care permit dezvoltarea de aplicatii care sa poata fi configuratepentru exploatarea lor in diverse zone ale globului, utilizandlimba si particularitatile legate de formatarea datei, numerelor sau amonedei din zona respectiva.
36
CAPITOLUL 3:PREGĂTIREA MEDIULUI DE LUCRU 3.1. Instalare NetBeans NetBeans este un proiect open-source, cu o bază de utilizatori foarte mare, o comunitate în creştere şi peste 100 de parteneri (în creştere!) din toată lumea. Sun Microsystems a fondat proiectul open source NetBeans în iunie 2000 şi continuă să fie principalul sponsor al proiectului. Astăzi există două produse: NetBeans IDE şi platforma NetBeans. NetBeans IDE este un mediu de dezvoltare - un instrument pentru programatori, pentru scrierea, compilarea, testarea, depanarea, proiectarea şi instalarea programelor. Este scris în Java - dar poate accepta orice limbaj de programare. De asemenea, există un număr imens de module pentru extinderea NetBeans IDE. NetBeans IDE este un produs gratuit, fără restricţii legate de modul de utilizare. De asemenea, este disponibilă Platforma NetBeans; o bază modulară şi extensibilă, utilizată drept conector software pentru crearea aplicaţiilor desktop puternice. Partenerii ISV oferă Plugin-uri cu valoare adăugată, care se integrează uşor în platformă şi care pot fi utilizate, de asemenea, la dezvoltarea propriilor instrumente şi soluţii. Ambele produse sunt open-source şi gratuite pentru uz comercial şi necomercial. Codul sursă este disponibil pentru reutilizare, conform Common Development and Distribution License (CDDL - Licenţa de distribuţie şi dezvoltare comună). Aplicatia BattleShip a fost realizată in mediul de dezvoltare NetBeans IDE 6.7. Acesta se downloadeaza gratut de pe www.netbeans.org. Pentru a putea lucre in acest mediu trebuie sa fie instalat impreuna cu JDK, această platform fiind necesară pentru a putea realiza aplicatii Java. JDK poate fi downloadează gratuit de pe java.sun.com. NeatBeans IDE se instaleaza pe computer in functie de preferintele utilizatorului (unde sa fie instalat, update-uri). Dup ace a fost instalat la rularea in executie a mediului Netbeans IDE va aprea un splashscreen cum este aratat mai jos:
37
Dupa incarcarea modulelor necesare rulării, va incepre execuția propriu-zisă a medului de dezvoltare.
38
Dupa această etapă, utilizatorul poate să: creeze noi aplicatii java, să deschidă proiecte (realizate in NeatBeans), sa vizualizede demo-uri pentru a întelege cum se lucreaza cu NetBeans etc. Cu ajutorul acesui mediu se pot crea foarte usor fisiere executabile (jar), cu ajutorul cărora aplicația poate fi rulata independent, singura condiție fiind ca pe calculatorul unde este rulată să existe instalat JVM(Java Virtual Machine). Pentru aplicatii mai complexe pot fi adaugate librarii, jar-uri (JMathTools, metadataextractor etc), in functie de cerintele aplicatie
3.2. Configurare client-server Pentru a rula aplicația Battleship este necesar ca pe calculatorul unde se va executa server-ul,dacă este instalat sistemul de oprare Windows, firewall-ul sistemului de oprare să fie dezactivat pentru a permite conectarea cilentilor la server. Pentru această aplicație nu trebuie instalat nici un program, doar JVM pe computer.
39
CAPITOLUL 4:DESCRIEREA APLICATIEI 4.1. Introducere Cel mai întâlnit model de programare a aplicaţiilor de reţea poartă numele şi de aplicaţii Client-Server. Conceptul este simplu: o maşină client face o cerere pentru o informaţie sau trimite o comandă la un server; ca răspuns, serverul trimite datele cerute sau rezultatul comenzii. De cele mai multe ori, serverul răspunde numai la clienţi; nu iniţiază comunicaţiile. Aşadar, funcţia serverului este de asculta pentru o conexiune. Aceste lucru este realizat printr-un obiect server care a fost special creat. Funcţia clientului este de a încerca să stabilească o conexiune cu serverul pentru care este creat un obiect client. Odată stabilită conexiunea, se poate observa că la cele două capete (server şi client), conexiunea este transformată într-un obiect IO Stream şi din acel moment aceasta poate fi tratată ca şi cum sar scrie sau s-ar citi dintr-un fişier. La nivelul transport, internetul are două protocoale principale: User Datagram Protocol (UDP, neorientat - conexiune) si Transmission Control Protocol (TCP, orientat conexiune). UDP este un protocol simplu, care nu
asigură verificarea erorilor sau controlul
fluxului, astfel fiind necesar ca aplicaţia să efectueze aceste verificări; se foloseşte cu precădere la streaming multimedia. TCP este un protocol care asigură corectitudinea datelor, efectuând atât verificarea erorilor cât şi controlul fluxului; este protocolul de bază pentru transmiterea informaţiilor în reţea . Avantajele utilizării acestui protocol: este un protocol de reţea rutabil suportat de majoritatea sistemelor de operare; reprezintă o tehnologie pentru conectarea sistemelor diferite; Utilizează utilitare de conectivitate standard pentru a accesa şi transfera date între sisteme diferite; este un cadru de lucru robust, scalabil între platforme client / server; reprezintă o metodă de acces la resursele Internet; permite comunicarea într-un mediu eterogen, deci se pretează foarte bine pentru conexiunile din Internet (care este o reţea de reţele eterogene atât din punct de vedere hardware, cât şi software);
40
furnizează un protocol de reţea rutabil, pentru reţele mari, fiind folosit din acest motiv drept protocol de interconectare a acestor reţele; TCP/IP este o suită de protocoale, dintre care cele mai importante sunt TCP şi IP, care a fost transformat în standard pentru Internet de către Secretariatul pentru Apărare al Statelor Unite, şi care permite comunicaţia între reţele eterogene (interconectarea reţelelor). În această lucrare am exemplificat modul de funcţionare al protocololului TCP prin intermediul unor aplicaţii client-server(BattleShip).
4.2.Structura aplicatiei Aplicatia conține de fapt două aplicații care rulează separat: un server si un client, fiind realizată in acest mod deoarece pe calucaltorul pe care este rulat Serverul, nu e obligatoriu sa fie rulat Clientul si invers. Aplicatia Server BattleShipServer este o aplicație realizată in Java având următoarele atribuții: -
Creează uun socket pentru a comunica cu clienții
-
Primește date de la clienți
-
Trimite date la clienți
Aceasta aplicație este o aplicație multi-client, adcă la un moment dat la server pot fi conectați mai mulți clienți, BattleShipServer are in componență un singur pachet PacServer care conține patru clase Java: -
ChatCommunication
-
ChatServer
-
ClientObject
-
CommonSettings
Structura claselor: ChatComunication
41
ChatServer
ClientObject
42
CommonSettings
În acest modul au fost definite anumite comenzi pentru a putea distinge clienții conectați, pentru a trimite mesaje la toți clienții sau numai la naumiți clienți etc astfel: -
HELO- inițializaeza conexiunea la server.
-
QUIT- inchide conexiunea pentru clientul de la care s-a primit comanda
-
MESS – trimite un mesaj general la toți clienții
-
PRIV – trimite un mesaj la un anumit client
Aplicația
este
responsabilă
cu
evidența
clinților
conectați,
usernam-ul
si
primirea,trimiterea de mesaje. Clasa principală a acestei aplicații este ChatServer, care implementeaza interfața grafică pentru comunicarea cu utilizatorul, thread-urile pentru comuncarea cu clienții, trimiterea mesajelor către clienți, adăgarea clienților conectați, stergerea clienților in momentucl cand conexiunea către aceștia a fost închisă. Aplicației BattleShipServer va arăta, in momentul execuției, astfel:
43
După apasarea butonului START SERVER, serverul este pornit fiind disponibil celor care doresc să joace acest joc, si care au aplicația client.
In acest moment, aplicația a creat un socket pe portul 1436, si așteaptă clientii care doresc să se conecteze. Dacă un client se conectează la server, acesta av creea un thread (fir de execuție) separat pentru deserirea lui, iar când clientul trimite comanda QUIT și firul de execuție corespunzător va fi inchis. Acest lucru se realizeaza prin intermediul clasei ChatCommunication, care gestioneaza mesajele primite, lanseaza in execuție thread-ul corespunzator fiecărui client folosind metota run(), metodă apelata in momentul lansării în execuție a unui thread si răspunde cererilor clientului: public void run() { while(thread != null) { try { RFC = inputstream.readLine(); if(RFC.startsWith("HELO")) 44
{ Parent.AddUser(socket,RFC.substring(5)); } if(RFC.startsWith("QUIT")) { Parent.RemoveUser(RFC.Substring(5,RFC.indexOf("~")), RFC.substring (RFC .indexOf("~")+1),REMOVE_USER); QuitConnection(); } { if(RFC.startsWith("MESS")) { Parent.SendGeneralMessage(socket,RFC.substring(RFC.indexOf(":") +1)
,RFC.substring(RFC.indexOf("~")
+1,RFC.indexOf(":")),RFC.substring(5, RFC.indexOf("~"))); } if(RFC.startsWith("PRIV")) { Parent.SendPrivateMessage(RFC.substring(RFC.indexOf("~")+1), RFC.substring(5,RFC.indexOf("~"))); } }
Clasa ClientObject conține metode care returnează variabilele necesare pentru evidența clientilor: username,socket,thread.
public void setSocket(Socket socket) { ClientSocket = socket; }
45
public void setUserName(String UserName) { ClientUserName = UserName; } public Socket getSocket() { return ClientSocket; } public String getUserName() { return ClientUserName; }
Aplicația Client BattleShipClient este, de fapt, aplicația cu ajutorul căreia utilizatorul paote sa joace BattleShip. Pentru conectarea la server folosește socket-uri și thread-uri, iar pentru desenarea navelor, desenarea țintei, a loviturilor foloseste API-ul Java2D. Aceasta aplicație conține patru pachete: -
BattleShipSingle:conține clasele Java necesare utilizatorului sa joace jocul singur,cu calculatorul.
-
Main: in acest pachet este prezentă clasa principala a aplicației.
-
PacClient: clasele necesare conexiunii la server
-
BattleShip: clasele pentru jocul în rețea.
Pachetul BattleShipSingle conție clasele: -
BattleShipSingle este clasa principală pentru acest pachet, aceasta fiind lansată în execuție când utilizatorul joacă cu computerul. În această clasă este implementată intefața grafică cu utilizatorul si sunt adaugate celelate componente.
-
Game adaugă componentele necesare jocului
-
GridArea este clasa care conține matricea cu pozițiile navelor, event-urile pentru click si metodele pentru validare pozițiilor navelor. 46
-
PlayingField este o clasă cu ajutorul căreia se poziționează navele și conține metodele care verifică daca o afost lovită sau nu o nava, metodele de desenare a navelor si doua clase care extind clasa GridArea (LeftField,RightField) pentru a putea juca jocul.
-
RunGame este clasa cu ajutorul căreia je jocaă jocul Battleship. Aceasta clasă conține un thread care gestioneaza evenimente și desenarea.
-
Sound este clasa care implementeaza sunetele pentru diferite acțiuni ale jucătorului.
Structura claselor: BattleShipSingle
Game
GridArea
PlayingField
47
RunGame
Sound
Desenarea navelor și a țintei precum și a imaginiilor cu lovit sau nu este realizată cu ajutorul API-ului Java2D prin intermediul metodei paint() care este apelată ori de cate ori se modifică ceva. Pentru desenarea imaginilor cu lovit sau nu și a țintei:
48
public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; int current; for (int y=0; y<10; y++) for (int x=0; x<10; x++) { if (area[x][y]!=0&&bturn==1) { current = area[x][y]/10; if ((current/10)%10!=0)
/
{ if (current%10!=0) g2.drawImage(PlayingField.fire, 25*x, 25*y, this); else g2.drawImage(PlayingField.splash, 25*x, 25*y, this); } } } if (cursorLocation!=null&&bturn==1) g2.drawImage(PlayingField.target,
25*(int)cursorLocation.getX(),
25*(int)cursorLocation.getY(), this); }
Pachetul Main conție o singura clasă: MainGui: Această clasă este folosită in momentul pornirii aplicației pentru ca utilizatorul să aleaggă modul cum va juca: vs computer sau multyplayer.
49
Pachetul PacClient are în componență următoarele clase: -
ChatClient clasa principala cu ajutorul căreia se implementează interfața pentru conectarea la server și thread-urile necesare acestei conexiuni.
-
CommonSettings conține setări pentru client: portul de ascultare, titlui, dimensiuni
-
ListViewCanvas metodele pentru adăugarea clienților conectați la server, stergerea lor, trimiterea de mesaje
-
PrivateChat2 este clasa care trimite mesaje la anumiți useri, primește mesaje de la anumiți useri. Cu ajutorul acestei clase jocul poate fi jucat de doar doi clienți, char dacă la server sunt conectați mai mulți useri.
-
Game este clasa cu ajutorul căreia utilizatorul pote sa aleaga dacă doreste să joce jocul cu userul de la care a venit cererea sau nu.
-
NoGame apare in momentul când userul la către care utilizatorul a trimis cererea pentru a juca nu a fost de acord.
-
InformationDialog cu ajutorul acestei clase clientul introduce usernam-ul si adresa server-ului
-
TapPannel este calsa care afișeaza userii conectatii si cu ajutorul căreia pot fi trimise cereri pentru a juca BattleShip în rețea.
Structura claselor ChatClient
CommonSettings
50
ListViewCanvas
PrivateChat2
51
TapPannel
Game
Pachetul BattleShip conține aceeleași clase ca și pachetul BattleShipSingle singura difereță fiind în clasa RunGame, care nu mai ia rezultatetele de pe calculatorul gazda ci asteatptă sa primească de la server.
Structura acestei clase este:
52
4.3. Simularea jocului Pentru inceput trebuie pornit serverul:
După ce serverul a fost pornit, la acesta se pot conecta mai mulți client. Jaocul se poate juca în rețea dacă există cel puțin doi client conectați la un moment dat. La lansarea in execuție a aplicației BattleShipClient se va deschide o fereastră din care utilizatorul trebuie sa aleaga modul in care va juca: 53
-
Cu computer-ul
-
Multiplayer
Dacă va allege “New game”, se va deschide fereastra pentru a juca BattleShip cu computer-ul și cu ajutorul căreia va așeza navele.
După ce navele au fost așezate, se poate începe jocul.
54
După ce utilizatorul dă click pe o căsuță aceasta se colorează în funcție dacă a fost lovită o navă a computer-ului sau nu. După ce utilizatorul a a dat click este randul computerului. Jocul se termină când computerul sau utilizatorul a lovit toate navele celuilat.
Dacă utilizatorul vrea să joace în rețea și alege opțiunea “Multyplayer”, se va deschide o fereastră unde trebuie să introducă username-ul și adresa serverului.
55
După ce a fost introdus Nickanme-ul si adresa server-ului, la apăsarea butonului Connect, aplicația se va conecta la server dacă acesta este pornit. Dacă serverul nu este pornit, se va afișa un meaj de eroare. După conectare, vor fi afișați toți clienții conectați iar pentru a juca BattleShip cu unul din ei, se selectează numele acestuia și se apasă butonul “Start game”.
56
La apăsarea butonului ‘Start game” un mesaj va trimis catre utilizatorul al cărui nume este selectat. La randul lui acesta va primi un mesaj cu întrebarea dacă dorește sa joace BattleShip cu clientul de la care s-a primit mesajul
Dacă acesta este de acord se va deschid o nouă fereastră unde cei doi trebuie sa își așeze navele, iar după ce amândoi ș-au așezat navele pot începe jocul Lovitura de început o are cel care trimite cererea pentru joc. Fereastra pentru jucătorul care are lovitura de început va arăta astfel:
57
După ce a dat click pe o poziție de câmpul oponentului, pe acea poziție va apărea o imagine in funcție dacă a lovit o navă sau nu. După ce a dat click va trebui să astepte ca și celalat jucător să facă o mutare.
Utilizatorul care a fost de acord să joce BattleShip, după ce a așezat navele va trebui sa aștepte prima lovitură de la celălalt.
58
După ce acesta a efectuat prima mutare, pe campul sau va apărea locul unde a dat click celalat si dacă a lovit o navă sau nu. În acest moment, va fi randul lui sa lovească.
Așa va arăta tabla de joc a utilizatorului Mihai dupa câteva mutări. 59
Jocul se va termina când unul dintre cei doi jucători a reușit să lovească toate navele celuilat. În acel moment, la fiecare utilizator va fi afișată o fereastră care îl anunță ca a castigat sau a pierdut.
După apăsarea butonului OK se va deschide fereastra principala cu userii și pot începe alt joc in modul explicat mai sus.
60
CAPITOLUL 5: CONCLUZII În ultimul deceniu, arhitectura client/server a ajuns cel mai cunoscut model pentru aplicatiile de retea. Astăzi, multe dintre aplicaţiile cu care suntem familiarizaţi sunt client/server: Web-ul, e-mail, ftp, telnet, şi aşa mai departe. Chiar dacă tot mai mulţi gameri îşi îndreaptă atenţia către console, viitorul jocurilor pentru PC pare unul din ce în ce mai sumbru curile pentru PC vor evolua in tandem cu procesoarele, placile grafice si monitoarele. Conform viziunii lui Taylor, ecrane cu rezolutii impresionante, de 3800 x 2400 px, vor fi disponibile in anii urmatori, avand dimensiuni de cel putin 30". Jocurile si motoarele ce stau la baza lor vor evolua si ele, ajungand pana la a simula indeaproape realitatea, dar pentru aceasta vor fi necesare procesoare grafice foarte puternice. Taylor considera vital sa se accorde atentie viziunilor creatorilor de jocuri si simularea dorintelor si ideilor lor cat mai fidel, adaugand din plin elemente "eye candy" pentru a atrage si capta utilizatorul printr-o grafica de senzatie. Taylor uită că principalul consumator de jocuri pentru PC are o varstă cuprinsă intre 15 si 25 de ani şi nu dispune de conturi in banca cu multe zerouri. Pentru el, a avea nevoie de un sistem de zeci de mii de dolari pentru a putea rula ultimele titluri din Diablo sau Need for Speed nu este o optiune viabilă. Deloc. Asadar, conform planurilor de viitor ale reprezentantului Nvidia, jocul pentru PC se va transforma dintr-un produs de masă intr-unul exclusivist, ce va fi admirat dar si urat in acelasi timp de cei multi, care nu il vor putea rula pe sistemele lor de acasa. Reteta jocurilor cu grafica extraordinara nu este neaparat una de succes. A se vedea cazul actual al consolelor PlayStation 3, de departe cele mai potente şi calitative, care sunt cu mult mai prost vandute decat concurentele Nintendo Wii? De ce? Pentru ca un joc este un angrenaj complex intre grafică, costuri, cerinte şi mai ales gameplay. Abia in momentul în care vor exista produse care sa bifeze toate acestea puncte, vom putea spune ca viitorul jocurilor pentru PC va fi altfel decat acum. Jocurile care folosesc o arhitectură client-server au reprezintă viitorul jocurilor pc, video, console find folosite de toate categoriile de vasta de la copii de 4 ani si pana la varstnici. Jocurile multyplayer reprezinta viitorul jocurilor video indiferent pe ce vor fi ele jucate: PC sau console.
61
BIBLIOGRAFIE •
M. Tim Jones - BSD Sockets Programming from a Multi-Language Perspective, Charles River Media, 2004
•
G. Stoian, C.-I. Popirlan, Tehnologii java pentru dezvoltarea aplicatiilor. Editura Universitaria, Craiova, 2009.
•
Michael Morrison - Internet Game Programming with Java, Sams.net Publishing, 1996
•
Bruce Eckel-Thinking in Java, Prentice Hall,2006
•
Jerry Ablan –Developing Intranet Applications with Java, Sams.net Publishing, 1996
•
Kenneth L. Calvert-TCP/IP Sockets in Java, The Morgan Kaufmann Practical Guides Series
•
http://www.calsoftlabs.com/whitepapers/java-networking.html
62