Notiuni Introductive Jocuri

CUPRINS

CAPITOLUL 1

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)

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 MMORPG-uri.

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

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

Importanța Internetului realizarea aplicațiilor bazate pe arhitectura client-server

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.

Evolutia limbajului JAVA

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.

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.

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.

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ă C-ului 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 :

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 :

Private – accesibile doar obiectelor din aceeasi clasă

Protejate – accesibile obiectelor din aceeasi clasă si din subclasele clasei respective

Prietenosase – (nivelul de accesibilitate prestabilit) accesibile tuturor claselor din pachetul curent

Publice – accesibile tuturor claselor din orice pachet

Programarea în limbajul Java

5. Caracteristicile de baza al limbajului Java

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)

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

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.

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.

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

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;

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.

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.

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ă:

Î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:

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:

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.

Î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()

î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

Exemplul 3. Chat (o conversație) între două calculatoare.

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

// Unitatea de compilare Server.java

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:

î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 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.

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 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.

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().

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.

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.

Thread in executie – Thread-ul a fost lansat in executie cu metoda start(). Este thread-ul pe care procesorul il executa in acest moment.

Thread gata de executie (runnable) – Thread-ul a fost startat dar nu se afla in executie in acest moment.

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.

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.

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.

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.

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)

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.

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.

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()

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

// 2. Folosirea unei copii

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

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-and-Feel, 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.

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:

Dupa incarcarea modulelor necesare rulării, va incepre execuția propriu-zisă a medului de dezvoltare.

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.

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 s-ar 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);

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

ChatServer

ClientObject

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:

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:

Clasa ClientObject conține metode care returnează variabilele necesare pentru evidența clientilor: username,socket,thread.

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.

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

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:

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.

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

ListViewCanvas PrivateChat2

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:

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:

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.

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 computer-ului.

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.

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”.

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:

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.

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.

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.

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.

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

Similar Posts