Battaglia Navale

1,864 views

Published on

Gioco della Battaglia Navale in multiplayer con CLI (Command Line Interface) in ambiente Unix.

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,864
On SlideShare
0
From Embeds
0
Number of Embeds
48
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Battaglia Navale

  1. 1. UNIVERSITA DEGLI STUDI DI NAPOLI FEDERICO II Progetto diLaboratorio di Sistemi Operativi .:Traccia C:. A.A. 2007/2008 gr.3 Prof. A.Finzi Vanacore Paolo – 566/1539
  2. 2. Indice1 Contenuto del pacchetto software.............................................22 Guida duso..................................................................3 2.1 Il server................................................................3 2.1.1 Compilare ed installare il server: due modalità....................3 2.1.2 Compilare ed installare il server: il makefile.....................3 2.1.3 Compilare ed installare il server: lo script bash..................4 2.1.4 Esecuzione del server: esempio duso...............................5 2.1.5 Disinstallare il server............................................7 2.1.6 Il file di log....................................................7 2.2 Il client................................................................8 2.2.1 Compilare, installare e disinstallare il client....................8 2.2.2 Esecuzione del client: esempio duso ..............................93 Il protocollo di comunicazione al “livello software”.........................12 3.1 La “FASE I” del protocollo di comunicazione.............................12 3.2 La “FASE II” del protocollo di comunicazione............................154 Considerazioni..............................................................18 4.1 Server: la mutua esclusione.............................................18 4.2 Server: segnali e TSD...................................................19 4.3 Client: una primitiva fuori programma, lI/O multiplexing................22 4.4 Note: possibili miglioramenti...........................................225 Codice sorgente.............................................................24 1
  3. 3. 1 Contenuto del pacchetto softwareE di seguito riportato il contenuto del pacchetto software (file e directory)con una breve descrizione degli elementi che lo compongono:radice:client - cartella contenente i files per il clientDocumentazione.pdf- la presente documentazioneserver - cartella contenente i files per il server./client:src - cartella contenente i file sorgente per il client./client/src:client.c - file sorgente con funzione main per il clientistruzioni - istruzioni in linea sul giocolib - directory delle librerie per il clientMakefile - make file per compilare/installare/disinst. il client./client/src/lib:FASI.c - sorgente contenente le funzioni per la gestione delle varie fasi di comunicazione con il serverFASI.h - header file contenente i prototipi delle funzioni implementate in FASI.csocketTools.c - sorgente contenente alcune funzioni per lI/O su socketsocketTools.h - header file dei prototipi delle funzioni implementate in socketTools.c./server:src - directory contenente i files sorgente per il server./server/src:compileMode.sh - script di shell bash per la compilazione del server con specifica di modalità: “silent” o “verbose”lib - directoty contenente le librerie usate per il serverMakefile - make file per la compilazione/installazione/disinstallazione del serverserver.c - file sorgente contenente la funzione main del server./server/src/lib:clientQueue - directory contenente la definizione di strutture dati e funzioni per mantenere le informazioni associate ai client e la gestione di una coda “dei client pronti”threadStartFunctions – directory contenente le funzioni davvio dei threads ed alcune funzioni accessorie./server/src/lib/clientQueue:clientQueue.c - implementazione funzioni per la coda “dei client pronti”clientQueue.h - dichiarazione funzioni implementate in “clientQueue.c”./server/src/lib/threadStartFunctions:socketIOLib - directory contenente i sorgenti per alcune funzioni di I/O su socketthreadSF.c - file sorgente contenente limplementazione delle funzioni di avvio dei threads ed alcune funzioni accessoriethreadSF.h - file header contenente la dichiarazione delle funzioni implementate in threadSF.c ed alcune macro per le varie fasi di comunicazione con i client./server/src/lib/threadStartFunctions/socketIOLib:socketIOLib.c - file sorgente contenente limplementazione di alcune funzioni per lI/O su socketsocketIOLib.h - header file contenente i prototipi delle funzioni implementate in socketIOLib.c 2
  4. 4. 2 GUIDA DUSO 2.1 Il server In questa sezione viene analizzata la procedura da seguire per una corretta compilazione, installazione/disinstallazione ed esecuzione del server di gioco. Vengono dapprima trattate le due modalità di compilazione disponibili: tramite makefile (sez. 2.1.2) e tramite script di shell bash (sez. 2.1.3). Quindi viene mostrato un esempio duso attraverso il quale saranno analizzati i vari aspetti dellesecuzione del server (sez. 2.1.4). Nelle ultime due sottosezioni viene mostrato luso del makefile per disinstallare il server (sez. 2.1.5) e trattato il formato del file di log sul quale il server annota alcune informazioni durante la sua esecuzione (sez. 2.1.6). 2.1.1 Compilare ed installare il server: due modalità Per la compilazione-installazione del server sono stati predisposti due file al fine di automatizzare tale processo. La compilazione-installazione del server può pertanto avvenire scegliendo una delle seguenti alternative: • Compilazione-installazione tramite makefile1; • Compilazione-installazione tramite script di shell bash. Le due alternative differiscono unicamente per la possibilità che offre lo script bash di impostare la modalità “verbose” o “silent” del server. Luso del makefile, invece, comporta la compilazione del server secondo lultima modalità impostata2. Compilando con specifica della modalità “verbose”, durante la sua esecuzione, il server mostrerà sullo stdout alcune informazioni circa la sua attività (sez. 2.1.4), mentre, in modalità “silent”, non verrà fatto uso di stdout3. Non vi sono ulteriori differenze tra le due modalità di compilazione. In entrambi i casi il risultato è una cartella “/server/bin/” contenente tutto loccorrente allesecuzione del server. 2.1.2 Compilare ed installare il server: il makefile Il processo di compilazione ed installazione tramite makefile consta di due “classici” comandi: “make” e “make install”. Il comando “make” esegue la compilazione ed il linking dei sorgenti e librerie necessarie. Il risultato di tale comando è un insieme di file oggetto collocati nelle stesse directory dei rispettivi sorgenti. Il comando “make install” crea, alloccorrenza, lalbero delle directory di radice “/server/bin/”, quindi sposta i file oggetto allinterno di tale albero di directory.1 Testato con: GNU Make 3.81.2 Lo script bash modifica opportunamente la definizione di una macro - “VERBOSE” - allinterno dei file sorgente:“/server/src/server.c” e “/server/src/lib/threadSF.h”. Dopo tale modifica, quindi, viene eseguito automaticamente “make” e “makeinstall”. Per questo motivo la compilazione “diretta” tramite “make” conserva inalterata la definizione della macro allultimo valoreimpostato.3 In entrambi i casi, alloccorrenza di eventuali errori, il server farà uso di stderr. 3
  5. 5. Di seguito viene riportato un esempio di compilazione tramite makefile: paolo@debian:~/server/src$ ls -l totale 28 -rwxrwxrwx 1 root root 1714 2008-07-01 21:26 compileMode.sh drwxrwxrwx 1 root root 0 2008-06-24 05:54 lib -rwxrwxrwx 1 root root 3575 2008-07-03 17:31 Makefile -rwxrwxrwx 1 root root 16537 2008-07-01 21:56 server.c paolo@debian:~/server/src$ make gcc -c lib/threadStartFunctions/socketIOLib/socketIOLib.c -o lib/threadStartFunctions/socketIOLib/socketIOLib.o gcc -c lib/clientQueue/clientQueue.c -o lib/clientQueue/clientQueue.o gcc -c lib/threadStartFunctions/threadSF.c -o lib/threadStartFunctions/threadSF.o gcc -pthread lib/threadStartFunctions/socketIOLib/socketIOLib.o lib/clientQueue/clientQueue.o lib/threadStartFunctions/threadSF.o server.c -o server paolo@debian:~/server/src$ make install Inizio installazione in: ../bin Installazione completata. paolo@debian:~/server/src$ Dalle righe riportate è possibile osservare il processo di compilazione tramite gcc1 a seguito del comando “make” e le “informazioni” dinstallazione (o meglio “spostamento”) nella cartella di destinazione (“../bin/”) a seguito del comando “make install”. 2.1.3 Compilare ed installare il server: lo script bash Lo script di shell bash realizzato - “/server/src/compileMode.sh” - automatizza lintero processo di compilazione ed installazione del server. Per avviare la compilazione del server è sufficiente2 eseguire lo script con uno dei due argomenti: [“verbose”|“silent”]. Si riporta, di seguito, un esempio di compilazione tramite script con richiesta di modalità “silent” per il server: paolo@debian:~/server/src$ ls -l totale 28 -rwxrwxrwx 1 root root 1714 2008-07-01 21:26 compileMode.sh drwxrwxrwx 1 root root 0 2008-06-24 05:54 lib -rwxrwxrwx 1 root root 3575 2008-07-03 17:31 Makefile -rwxrwxrwx 1 root root 16537 2008-07-01 21:56 server.c paolo@debian:~/server/src$ ./compileMode.sh silent Compiling in silent mode... gcc -c lib/threadStartFunctions/socketIOLib/socketIOLib.c -o lib/threadStartFunctions/socketIOLib/socketIOLib.o gcc -c lib/clientQueue/clientQueue.c -o lib/clientQueue/clientQueue.o gcc -c lib/threadStartFunctions/threadSF.c -o lib/threadStartFunctions/threadSF.o gcc -pthread lib/threadStartFunctions/socketIOLib/socketIOLib.o lib/clientQueue/clientQueue.o lib/threadStartFunctions/threadSF.o server.c -o server Inizio installazione in: ../bin1 Testato con gcc (GCC) 4.1.2 20061115.2 E sottintesa la necessità di possedere adeguate credenziali per lesecuzione del file. 4
  6. 6. Installazione completata. paolo@debian:~/server/src$ Come nel caso della compilazione tramite makefile, il risultato finale del processo di compilazione ed installazione del server è un albero di directory di radice “/server/bin/” contenente tutto il necessario allesecuzione del server. 2.1.4 Esecuzione del server: esempio duso A seguito della procedura di compilazione ed installazione del server è possibile accedere alla directory “/server/bin/” il cui contenuto è il seguente: paolo@debian:~/server/bin$ ls -l totale 24 drwxr-xr-x 4 paolo paolo 4096 2008-07-02 17:42 lib -rwxr-xr-x 1 paolo paolo 23890 2008-07-02 17:42 server Dove: • la cartella “lib” contiene i files oggetto delle librerie utilizzate per la compilazione; • “server” è il file eseguibile per avviare il server di gioco. A questo punto è possibile avviare il server utilizzando la seguente sintassi: ./server <port> <timer(seconds)> Dove i parametri hanno il seguente significato: 1. <port> la porta dascolto 2. <timer(seconds)> è il timer1, espresso in secondi, indicante la durata massima di ogni singola partita. Ipotizzando di aver eseguito la compilazione del server in modalità “verbose”2, eseguendo il seguente comando si avvia il server: paolo@debian:~/server/bin$ ./server 2000 500 Server listening on port:: 2000 - Game timer: 500s La prima riga di output del server (“Server listening ...”) indica, come richiesto dalla specifica degli argomenti inseriti (“./server 2000 500”), che il server è attualmente in ascolto sulla porta 2000 ed il timer impostato per le partite è di 500 secondi. Al fine di analizzare alcune delle possibili informazioni che il server, compilato in modalità “verbose”, invia su stdout, si riporta una sezione desempio:1 Per conoscere il valore massimo che il timer può as sumere è possibile eseguire il server senza argomenti (“paolo@debian:~/server/bin$./server”). Nellultima riga di output verrà indicato il massimo valore che si può scegliere per il timer ed una sua approssimazione in ore. Ilvalore massimo per il timer equivale al massimo intero (con segno – int) rappresentabile sullarchitettura che esegue il server, per questomotivo è un valore che potrebbe variare.2 Si considera questa ipotesi in quanto la modalità “silent” non prevede alcun output su stdout e quindi ci sar ebbe poco da analizzare. 5
  7. 7. paolo@debian:~/server/bin$ ./server 2000 500Server listening on port:: 2000 - Game timer: 500s -->* Connection activity:: 127.0.0.1 connected socket descriptor: 5 time event: Wed Jul2 19:22:53 2008 -><- Client activity:: 127.0.0.1 chosen nick: Paolo -><- Client activity:: 127.0.0.1 (Paolo) service request: 1 time event: Wed Jul 219:22:57 2008 -><- Client activity:: 127.0.0.1 (Paolo) flotta init time event: Wed Jul 2 19:22:58 2008 Details: 4: (0, 0) (1, 0) (2, 0) (3, 0) 3: (0, 1) (1, 1) (2, 1) 3: (0, 2) (1, 2) (2, 2) 2: (0, 3) (1, 3) 2: (0, 4) (1, 4) 2: (0, 5) (1, 5) 1: (0, 6) 1: (0, 7) 1: (0, 8) -><- Client activity:: 127.0.0.1 (Paolo) service request: 2 time event: Wed Jul 219:23:01 2008 -><- Client activity:: 127.0.0.1 (Paolo) service request: 3 time event: Wed Jul 219:23:03 2008 -><- Client activity:: 127.0.0.1 (Paolo) service request: 3 time event: Wed Jul 219:23:05 2008 -><- Client activity:: 127.0.0.1 (Paolo) service request: 4 time event: Wed Jul 219:23:05 2008 <--* Connection activity:: 127.0.0.1 disconnect nick: Paolo time event: Wed Jul 219:23:09 2008Server closing ...Server close.paolo@debian:~/server/bin$ Nella prima colonna è presente un simbolo ad indicare la “classe dappartenenza” dellevento occorso, nella seconda colonna viene specificato il tipo di evento seguito da alcuni dettagli che differiscono in base allevento ed infine, nellultima colonna, è presente la data e lora in cui è occorso levento. I possibili simboli, tipi di evento e dettagli sono specificati in tabella 1. Ovviamente, in caso di server compilato in “silent” mode, non si ha nessun output su stdout. Per terminare un server in esecuzione è necessario inviare un segnale di terminazione (SIGINT: Ctrl+c o SIGQUIT: Ctrl+) al relativo processo. Si ottiene una corretta chiusura del server anche attraverso linvio, al relativo processo, di un segnale di chiusura del terminale che gestisce il processo stesso (SIGHUP). simbolo tipo evento Dettagli -->* connessione di indirizzo ip del client e socket descriptor assegnatogli un client -><- attività di un indirizzo ip del client, nick scelto alla connessione, tipo di attività client effettuata e dettagli eventuali sullattività eseguita. (es. richiesta di un servizio al server1, inizializzazione flotta,...) -<>- interazione indirizzi ip e nick dei client, dettagli circa linterazione “tra due (es. inizio/fine di una partita) client” <--* disconnessione indirizzo ip del client disconnesso, eventuale nick. di un client Tabella 1. Simboli e corrispondenti eventi-dettagli nelloutput di un server compilato in “verbose mode” Come già accennato, durante la sua normale attività, il server1 Per conoscere la corrispondenza tra il numero che identifica una richiesta ed il tipo di richiesta è possibile visionare la definizione dellemacro con suffisso “_REQ” nellheader file “/server/src/lib/threadStartFunctions/threadSF.h” 6
  8. 8. effettua la scrittura di alcuni eventi allinterno di un file di log. Tale file, se non già esistente, sarà automaticamente creato dal server al primo avvio (“/server/bin/logfile”) (sez. 2.1.6). 2.1.5 Disinstallare il server Per “disinstallazione del server” sintende loperazione di rimozione di tutti i file e directory creati a seguito del processo di installazione. Quindi durante il processo di disinstallazione verrà rimosso tutto il contenuto della cartella “/server/bin/” (percorso predefinito di “installazione” definito allinterno del makefile) compreso leventuale file di log (“/server/bin/logfile”). Il processo di disinstallazione, come riportato nellesempio a seguire, si avvia tramite il comando “makefile clean”. paolo@debian:~/server$ ls -l totale 12 drwxr-xr-x 3 paolo paolo 4096 2008-07-03 18:17 bin drwxr-xr-x 2 paolo paolo 4096 2008-06-22 13:46 doc drwxr-xr-x 3 paolo paolo 4096 2008-07-03 18:17 src paolo@debian:~/server$ cd src/ paolo@debian:~/server/src$ make clean Attenzione! tutto il contenuto della cartella ../bin andrà perso (compreso il file di log) Premere INVIO per continuare, Ctrl+c per interrompere ... Pulizia in corso di: ../bin Pulizia completata. paolo@debian:~/server/src$ ls -l ../ totale 8 drwxr-xr-x 2 paolo paolo 4096 2008-06-22 13:46 doc drwxr-xr-x 3 paolo paolo 4096 2008-07-03 18:17 src 2.1.6 Il file di log Come già accennato, durante la sua esecuzione, il server effettua alcune operazioni di log su file. Tale file, se non esiste, viene automaticamente creato dal server e le operazioni future di scrittura saranno effettuate in append. La posizione del file allinterno del filesystem1 è la seguente: “/server/bin/logfile”. Passando ad analizzare il formato delle informazioni contenute in tale file si ha che: La prima colonna contiene la data dellevento mentre nelle successive colonne vengono specificati i dettagli dellevento. I TAG per gli eventi, nella seconda colonna, sono specificati in tabella 2.1 Come tutte le notazioni usate finora per la localizzazione di directory/files allinterno del filesystem anche questa volta si è usato unpercorso relativo alla posizione del pacchetto software. 7
  9. 9. Tag tipo evento DettagliSERVER avvio del porta dascolto ("listening port"); timer per le partite ("gameSTART server timer").Client connessione di indirizzo ip del client ("ip"); socket descriptor assegnatogliconn. un client ("c_sfd"). Game inizio partita nicknames dei client ("nick1 VS nick2"); indirizzi ip dei client ("ip1 start tra due client vs ip2").Game end fine di una nickname dei due giocatori("nick1 VS nick2"); punteggi della partita partita ("Score"); indirizzi ip dei client ("ip1 vs ip2"); - nel caso di fine prematura della partita a causa della disconnessione di uno dei player - lindirizzo ip ed il nickname del giocatore disconn. ("[ip nick disconnect]").Client disconnessione indirizzo ip del client ("ip"); nickname del client ("nick"); socketdisc. di un client descriptor ("c_sfd"); il punteggio al momento della disconnessione ("points"); data/ora di connessione ("since g.sett. mese g.mese hh:mm:ss anno"). Tabella 2. Tag per le informazioni contenute nel file di log, loro significato e dettagli 2.2 Il client In questa sezione vengono mostrati i passaggi per compilare, installare e disinstallare il client oltre ad alcune informazioni circa luso del client in esecuzione. 2.2.1 Compilare, installare e disinstallare il client Tutte e tre le azioni di compilazione, installazione e disinstallazione del client avvengono per mezzo delluso di un makefile: “/client/src/Makefile”. Come per il server, il comando “make” esegue la compilazione ed il linking “in place” del client, il comando “make install” crea una cartella “/client/bin/” nella quale posiziona i file oggetto del client ed infine, il comando “make clean” elimina ricorsivamente la cartella “/client/bin/” e tutto il suo contenuto. A scopo illustrativo si riporta un esempio della successione di comandi sopra descritti: paolo@debian:~/client$ ls doc src paolo@debian:~/client$ cd src/ paolo@debian:~/client/src$ make gcc -c lib/socketTools.c -o lib/socketTools.o gcc -c lib/FASI.c -o lib/FASI.o gcc lib/FASI.o lib/socketTools.o client.c -o client paolo@debian:~/client/src$ make install Inizio installazione in: ../bin Installazione completata. paolo@debian:~/client/src$ ls ../ bin doc src paolo@debian:~/client/src$ make clean Pulizia in corso di: ../bin Pulizia completata. paolo@debian:~/client/src$ ls ../ doc src paolo@debian:~/client/src$ 8
  10. 10. 2.2.2 Esecuzione del client: esempio dusoLa sintassi per eseguire il client è la seguente:./client <ip|serverName> <port>Dove: • <ip|serverName> è lindirizzo ip o lhostname del server di gioco al quale si desidera collegarsi. • <port> è la porta dascolto del server di gioco.Pertanto, è possibile notare che i seguenti due comandi sonoequivalenti: ./client localhost 3000 ./client 127.0.0.1 3000Allavvio del client, se la connessione con il server ha avutosuccesso (2-3), viene richiesto linserimento di un nickname (5):1. paolo@debian:~/client/bin$ ./client localhost 26642. Connecting to: 127.0.0.1:2664 ...3. Connected to: 127.0.0.1:26644.5. Inserire nickname:6. MyNickInserito il nick viene mostrato un menù con le varie opzionidisponibili (identificate da un intero): _______________________________1. Your nick: MyNick2. Your uniq ID: 153. Game timer: 300s4. _______________________________5. MENU6. 1.: Imposta la flotta7. 2.: Mostra players in attesa avversario8. 3.: Invisibile (current: ON)9. 4.: Gioca con player in attesa10. 5.: Mostra il campo11. 6.: Grid (current: OFF)12. 7.: Istruzioni13. 8.: ESCI14. _______________________________15. Scelta:In testa al menù (1-3) sono presenti alcune informazioni utili (nickscelto al momento della connessione, identificativo univoco personalee timer per le partite). Quindi seguono (6-13) le opzionidisponibili. 9
  11. 11. Il significato delle varie opzioni è il seguente:– “1.: Imposta la flotta” consente di schierare la flotta sul proprio campo di battaglia;– “2.: Mostra players in attesa avversario” consente di visualizzare i client connessi al server che stanno attendendo un avversario con cui giocare;– “3.: Invisibile (current: X)” con X = ON | OFF se X == “ON” non si verrà mostrati nelle “liste dei players in attesa” (opz. 2 e 4) degli altri client, con la conseguente impossibilità di essere scelti come avversari; se X == “OFF” si è mostrati nelle “liste dei players in attesa” (opz. 2 e 4) degli altri client, rendendosi così disponibili ad essere scelti per iniziare una nuova partita. NOTA: questa opzione è abilitata solo dopo aver schierato la flotta (opz. 1).– “4.: Gioca con un player in attesa” mostra la lista dei client in attesa di un avversario e consente di sceglierne uno per iniziare una partita; NOTA: questa opzione è abilitata solo dopo aver schierato la flotta (opz. 1).– “5.: Mostra il campo” mostra il campo di battaglia con la propria, eventuale, flotta;– “6.: Grid (current: X)” con X = ON | OFF abilita/disabilita la griglia per la visualizzazione del campo di battaglia;– “7.: Istruzioni” mostra alcune informazioni circa il gioco, il menù e le modalità di inserimento delle navi sul proprio campo;– “8.: ESCI” termina il programma client.Si evita di riportare in questo testo ulteriori informazioni circaluso del client che sono comunque visionabili tramite lopzione 7del menù di gioco.Può invece essere utile mostrare lesempio dinserimento di una nave.Supposto che si debba inserire una nave da 4 caselle e che la sivoglia posizionare alle coordinate (D5, D6, D7, D8) come segue: 10
  12. 12. - La tua flotta - A B C D E F G H I J K L M N O P Q R S T _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 0 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 0 1 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1 2 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 2 3 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 3 4 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 4 5 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 5 6 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 6 7 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 7 8 |_|_|_|4|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 8 9 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 910 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1011 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1112 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1213 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1314 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1415 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1516 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1617 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1718 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 1819 |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 19 A B C D E F G H I J K L M N O P Q R S TE sufficiente digitare:“D” come coordinata colonna,“5” per la coordinata di riga ed“S” per la direzione..:NAVE DA 4:.Coordinata Colonna (A, B, ..., T): DCoordinata Riga (0, 1, ...,19): 5Direzione D (N, S, E, O): SOvviamente, in alternativa, è anche possibile digitare:“D” per la colonna,“8” per la riga e“N” per la direzione..:NAVE DA 4:.Coordinata Colonna (A, B, ..., T): DCoordinata Riga (0, 1, ...,19): 8Direzione D (N, S, E, O): N 11
  13. 13. 3 Il protocollo di comunicazione al “livello software”Per come è stata organizzata la gestione dei client e delle partite, dal punto divista del server, è possibile scindere due fasi di comunicazione1:  FASE I – “client driven”: periodo di tempo che intercorre tra lavvenuta connessione del client e linizio di una partita;  FASE II – “server driven”: periodo di tempo tra linizio di una partita tra due client e la fine della stessa.Queste due fasi di comunicazione si succedono ciclicamente un numero “indefinito”di volte durante il periodo di connessione continuativa di un client al server2.Entrambe le fasi sono state realizzate sul concetto sul quale si basa ilparadigma client-server e cioè quello di: “servizio offerto e serviziorichiesto”.Durante la “FASE I” della comunicazione il client richiede – previa interazionedellutente con determinate opzioni del menù di gioco – servizi al server. Pertale motivo, la prima fase, è stata qualificata come “client driven”.Nella “FASE II”, qualificata come “server driven”, è il server a richiedereservizi, o meglio informazioni e cambiamenti di stato, al client.Nelle successive sottosezioni vengono analizzate le informazioni oggetto discambio durante le due fasi di comunicazione. 3.1 La “FASE I” del protocollo di comunicazione Come precedentemente accennato, in questa fase della comunicazione il server offre determinati servizi al client che ne richiede. Ogni servizio è univocamente identificato da un numero intero3. Le richieste di servizi vengono quindi effettuate dal client e riconosciute dal server per mezzo dellinvio e ricezione di questi id. interi. Tenendo presente che inizialmente il server è in attesa di ricevere la richiesta di un servizio, i servizi offerti durante la prima fase della comunicazione sono i seguenti: • SNDFLOTTA_REQ – id. 1: ➢ il client richiede al server di poter inviare la propria flotta (ciò avviene al termine dellimmissione delle navi da parte dellutente attraverso lopzione 1 del menù di gioco); ➢ Il server si predispone per la richiesta; ➢ il client invia la flotta; ➢ il server riceve e memorizza, in un opportuno ADT associato al client, la flotta, quindi attende una nuova richiesta; • RCVPLAYERS_REQ – id. 2: ➢ il client richiede la lista dei players online in1 E da notare che la struttura dei sorgenti del client (in particolare “/client/src/FASI.h” e “/client/src/FASI.c”) rispecchia “chiaramente” lasuddivisione delle due fasi di comunicazione.2 Il relativo non determinismo del numero di successioni cicliche delle due fasi di c omunicazione è stato adottato per consentire ad unclient di intraprendere più partite durante una stessa “sessione” di connessione.3 Ovviamente le associazioni (intero, servizio) allinterno del server equivalgono a quelle definite nel client.In particolare sono equivalenti le definizioni delle macro riguardanti i servizi di entrambe le fasi dicomunicazione. Tali macro sono definite in “/server/src/lib/threadStartFunctions/threadSF.h” e in“/client/src/lib/FASI.h”. 12
  14. 14. attesa di avversario (quando lutente sceglie le opzioni 2 e/o 4 del menù), quindi lattende. ➢ Il server invia la lista (estraendola da una coda dei client pronti) e si mette in attesa di una nuova richiesta di servizio. ➢ Il client legge la lista. • INVISIBLE_REQ – id. 3: ➢ il client richiede di attivare/disattivare linvisibilità (quando lutente sceglie lopzione 3 del menù); ➢ il server modifica “lo stato” del client (inserisce o elimina le info sul client da una coda dei client pronti) e si mette in attesa di ulteriori richieste; • STARTGAME_REQ – id. 4: ➢ il client richiede al server di iniziare una partita con un player in attesa (quando lutente sceglie lopzione 4, dopo unimplicita richiesta del client di “RCVPLAYERS_REQ”); ➢ il server attende di ricevere lidentificativo (intero univoco) del giocatore scelto come avversario dal client; ➢ il client invia lidentificativo dellavversario (scelto dallutente) ed attende una conferma dal server (0 se il player non esiste o non è disponibile, 1 altrimenti); ➢ il server riceve lidentificativo, verifica se il client richiesto esiste ed è disponibile (verifica se è presente in una coda dei client pronti) quindi:  Se il client richiesto è disponibile invia la conferma (un intero “1”) al client richiedente e passa alla FASE II.  Se il client richiesto non è disponibile avvisa il client richiedente (inviando lintero “0”), quindi attende nuove richieste. ➢ il client riceve la risposta dal server e, nel caso in cui si tratti di una conferma passa alla FASE II. Di seguito viene riportato un diagramma di sequenza nel quale si tiene conto della caratteristica del server di essere concorrente e multithreads1. Il diagramma illustra un ciclo tipico di servizi richiesti/offerti tra due client ed un server durante la prima fase della comunicazione.1 Ogni thread che gestisce questa fase di comunicazione con il client ad esso assegnato, ha come funzione davvio la funzione chiamata“clientController” definita in “/server/src/lib/threadStartFunctions/threadSF.h”. 13
  15. 15. Server inizializzaz., Tempo socket, binding, listening accept, allocazione ed inizializz. ADT per info client, ClientA Connect listening client create controller new thread AClientB login [nickName] Connect attesa ricezione flotta client create request [1] controller new thread invio Flotta B invio Flotta attesa login [nickName] [x, y]* ricezione lista request [2] request [1] lista client invio Flotta x1 invio lista invio Flotta [nick, id]*^ [x, y]* request [3] invisible switch request [2] x2 invio lista [nick, id]*^ Legenda attesa ricezione ID avversario █ Thread request [4] ___ inizio Partita Attività del server _ _ Attesa in ricezione invio ID avv. ___ attesa ricezione Attività “interna” [int] conferma [0|1] ___ > Invio/Ricezione informazioni invio Conferma ___ ▶ Creazione nuovo thread [0|1] x3 14
  16. 16. Al fine di analizzare il contenuto della “coda dei client pronti” (client in attesa di un avversario – opzione 3 [off] del menù) si sono individuati tre istanti di tempo: x1, x2 ed x3. Allistante t=x1 la coda dei client pronti risulta essere vuota, in quanto, dallavvio del server, nessun client ha effettuato una richiesta [3]: *clientReadyQueue null Allistante t=x2, a seguito di una richiesta [3] da parte del client A la coda dei client pronti contiene un unico elemento che punta ad un ADT associato al client stesso: *clientReadyQueue info Client A Allistante t=x3, se lidentificativo dellavversario scelto dal client B (a seguito della richiesta [4]) corrisponde allidentificativo del client A, allora, questultimo sarà rimosso dalla coda dei client pronti ed il thread clientController B invierà un intero “1” al client B. A questo punto si passa alla “Fase II” della comunicazione. In caso contrario il server invierà un intero “0” al client B e resterà in attesa di ulteriori richieste. E da notare che, a seguito di una richiesta [3] da parte di un client che ne comporta lo stato di “visibilità”1, il client stesso è ancora abilitato ad effettuare richieste al server. In questo caso, però, qualunque richiesta di servizio, diversa dalla [3], che il client effettui, viene preceduta da unimplicita2 richiesta [3] che lo rende “invisibile” (viene estratto dalla coda), quindi viene espletato il servizio richiesto ed infine si ha unulteriore implicita richiesta [3] atta a rendere nuovamente “visibile” (inserito in coda) il client. 3.2 La “FASE II” del protocollo di comunicazione In questa sezione sarà analizzata la seconda fase del protocollo di comunicazione che consiste nellinsieme delle possibili informazioni scambiate tra due client ed il server nel periodo di tempo intercorrente linizio di una partita e la fine della stessa. Tale fase viene definita “server driven” in quanto i client ricevono richieste di informazioni dal server che quindi “guida” la comunicazione. Come per la prima, anche per la seconda fase di comunicazione, sono stati definiti alcuni identificativi interi3 ad indicare le informazioni richieste dal server. Il server è, in questo periodo di tempo, rappresentato da un thread4 “chiamato playController” che gestisce la partita tra i due client. Inizialmente entrambi i client sono in attesa di ricevere richieste. Le possibili informazioni richieste dal server sono le seguenti:1 Cioè quando la richiesta comporta linserimento delle informazioni sul client allinterno della co dei client pronti, come avviene nel dadiagramma di sequenza precedente per il Client A dopo listante di tempo t=x2.2 Viene usato il termine “richiesta implicita” in quanto questo tipo di richiesta viene inviata dal client senza interazione con lutente.3 Nel client la definizione delle macro si trova nel file header: “/client/src/FASI.h”. Mentre per il server esse si trovanoin:”/server/src/lib/threadStartFunctions/threadSF .h”.4 La cui funzione davvio, definita in ”/server/src/lib/threadStartFunctions/threadSF .h”, è stata nominata: “playController”. 15
  17. 17. • SHOOTCOORD_REQ – id. 1: ➢ il server invia la richiesta al clientA (client “di turno”) ed attende linvio di una coppia di coordinate rappresentanti uno “sparo”; ➢ il clientA invia una coppia di interi (coordinate sparo lette da stdin); ➢ il server, riceve le coordinate, verifica se esse hanno colpito/affondato una nave del clientB1 calcolando un responso. • SNDSHTRESP_REQ – id. 2: ➢ il server richiede al clientA (client “di turno”) di poter inviare il responso in seguito ad un suo “sparo” (calcolato al termine della fase avviata da una richiesta di SHOOTCOORD_REQ); ➢ il client attende il responso riguardante il suo ultimo sparo effettuato; ➢ il server invia il responso al client; ➢ il client riceve il responso ed attende ulteriori richieste. • SNDADSCORE_REQ – id. 3: ➢ il server richiede al clientB di poter inviare le coordinate ed il punteggio dellultimo tiro del clientA; ➢ il client attende le coordinate del tiro dellavversario ed il suo punteggio; ➢ il server invia coordinate e punti al clientB; ➢ il client riceve coordinate e punti, quindi attende ulteriori richieste. • ENDGAME_REQ – id. 4: ➢ il server invia una “richiesta” (avviso) di fine partita; ➢ il client destinatario dellavviso attende di ricevere il “responso partita”; ➢ il server invia il “responso partita”, quindi passa alla FASE I (crea un thread clientController per gestire la comunicazione con il client); ➢ il client riceve linformazione, quindi, passa alla FASE I. Oltre alla definizione degli identificativi numerici sopra riportati, per questa fase di comunicazione, sono stati definiti anche i seguenti: • COLPITA_RESP – id. 1; AFFONDATA_RESP – id. 2; ACQUA_RESP – id. 3: identificano i tre possibili responsi di uno “sparo”. Sono inviati a seguito di una richiesta accordata di SNDSHTRESP_REQ ed, insieme alle coordinate del tiro, una richiesta di SNDADSCORE_REQ.1 Questa verifica viene effettuata su di unopportuna struttura dati mantenuta dal server per le infor mazioni dei client. E possibilevisionare tale struttura nel file: “/server/src/lib/clientQueue/clientQueue.h” 16
  18. 18. • WIN_RESP – id. 1; LOSS_RESP – id. 2; PLAYER_DISCONN – id. 3; EQUALS_RESP – id. 4: identificano il “responso di una partita”. Nellordine, partita vinta, persa, avversario disconnesso e partita patta. Si riporta di seguito un diagramma di sequenza atto a mostrare le informazioni scambiate tra il server (un thread “playController”) e due client: clientA e clientB. Inizialmente sipotizza che il turno di “sparo” sia del clientA. play ClientB controller ClientA acquisizione coordinate request [1] sparo da richiesta coordinate sparo stdin calcolo responso tiro invio coordinate sparo [x, y] (2*int) request [2] richiesta invio responso tiro attesa responso tiro invio responso tiro (1*int) attesa responso tiro request [3] avversario richiesta invio coord.- tiro e punti avv. invio coord.-punti tiro avv. [x, y, z] (3*int) Legenda █ Thread _ _ Attesa in ricezione ___ Attività “interna” ___ > Invio/Ricezione informazioni La fase rappresentata nel diagramma di sequenza si ripete ciclicamente e, ad ogni iterazione, i client vengono “scambiati di ruolo”. Si prosegue fin quando uno dei due player ha affondato tutte le navi dellavversario, un client si disconnette oppure alla scadenza del timer di gioco1.1 La gestione della fine di una partita, per scadenza timer viene mostrata nella sezione 4.2. 17
  19. 19. 4 Considerazioni Lapplicativo realizzato può essere considerato in versione “alpha” in cui è definita la struttura logica di base scelta al fine di rispettare le specifiche richieste. Sicuramente si possono apportare diverse modifiche ed aggiunte interessanti al progetto. Nellultima sezione ne vengono annotate alcune. Nelle sottosezioni che seguono vengono analizzati alcuni aspetti ritenuti di maggior interesse nei quali si mostra luso che si è fatto di alcune primitive che si sono rivelate fondamentali durante la “progettazione concettuale” e la stesura del codice. Al fine di rendere il presente testo il meno prolisso possibile si evita di riportare alcuni aspetti, altrettanto importanti, per i quali è comunque possibile visionare la documentazione interna. 4.1 Server: la mutua esclusione La gestione della comunicazione con ogni client è basata sulla gestione e manipolazione di alcune informazioni ad essi associate1. Come visto in sezione 3, tali informazioni vengono dapprima (durante la “FASE I”, sez. 3.1) manipolate da un thread la cui funzione davvio è chiamata “clientController”, ed in un secondo momento (“FASE II”, sez. 3.2) passano sotto la gestione di un thread “playController”. Quando un client imposta la visibilità, la struttura dati contenente le sue informazioni viene inserita allinterno di una coda dei client pronti2. Per ogni processo server in esecuzione esiste ununica coda dei client pronti alla quale più thread possono accedervi in maniera concorrente. Per questo motivo è stato associato alla coda un mutex3 atto a regolamentare le operazioni di I/O sulla coda. A tale scopo è stata definita4 la seguente struttura dati: struct mutexQueue{ struct list *queue; //>Pointer alla coda pthread_mutex_t *mutex; //>Mutua esclusione }; Un esempio di operazione che tiene conto dellaccesso concorrente alla coda è il seguente: /*! ENTRY SECTION !*/ //>Chiude il mutex associato alla coda if (pthread_mutex_lock(clientReadyMutexQueue->mutex)) perror("mutex_lock"), exit(1); /*! SEZIONE CRITICA !*/ //>Elimina dalla coda il client clientReadyMutexQueue->queue = removeElementByKey( clientReadyMutexQueue->queue, infoClient->c_sfd, &infoClientTmp); if (infoClientTmp == NULL) //>Se il client non era in coda lo inserisce clientReadyMutexQueue->queue = insertInHead( clientReadyMutexQueue->queue, infoClient);1 Per la struttura dati che mantiene queste informazioni si veda la definizione della “struct clientData” in“/server/src/lib/clientQueue/clientQueue.h”.2 La definizione della coda (linked list) e le funzioni accessorie per la sua gestione sono definite allinterno dellheader file“/server/src/lib/clientQueue/clientQueue.h”.3 Questo non è lunico caso in cui si fa uso diun mutex, ma lo si è scelto in quanto ritenuto di maggior interesse.4 La definizione è collocata in “/server/src/lib/threadStartFunctions/threadSF .h”. 18
  20. 20. /*! FINE SEZIONE CRITICA !*//*! EXIT SECTION !*/ //>Apre il mutex associato alla codaif (pthread_mutex_unlock(clientReadyMutexQueue->mutex) perror("mutex_unlock"), exit(1);Lesempio mostra le istruzioni che ogni thread “clientController” esegue inseguito ad ogni ricezione di richiesta INVISIBLE_REQ.Si può generalizzare in pseudo-codice la struttura di ogni segmento dicodice che accede alla coda per operazioni di I/O nel seguente modo:blocca_mutex(clientReadyQueue->mutex) //>Entry section (attesa passiva)... esegui I/O sulla coda ... //>Sezione criticasblocca_mutex(clientReadyQueue->mutex) //>Exit section4.2 Server: segnali e TSDAnche i segnali hanno avuto un ruolo fondamentale nello sviluppo delserver. Si è fatto uso dei segnali sia per unadeguata gestione dellaterminazione del server, sia per la gestione del timer delle partite.Per “adeguata gestione della terminazione del server” sintende un insiemedi operazioni da effettuare ad ogni chiusura. In particolare, loperazionefondamentale che viene eseguita è quella di annotare sul file di log (sez.2.1.6) levento di chiusura del server accompagnato dalla data ed oradellistante in cui questultima è avvenuta.Poiché il server, come da specifiche richieste, non riceve input da stdin,si è scelto di affidare il processo di terminazione ai seguenti segnali: • SIGINT (interruzione da terminale: “Ctrl+c”); • SIGQUIT (interruzione da terminale: “Ctrl+”); • SIGHUP (chiusura del terminale che gestiva il processo).Nella fase di inizializzazione del server, al suo avvio (main in“server/src/server.c”), viene registrato un gestore per i segnali soprariportati:if (signal(SIGINT, sig_hand) == SIG_ERR) //>Ctrl+c (interr. da terminale) perror("signal"), exit(1);if (signal(SIGQUIT, sig_hand) == SIG_ERR) //>Ctrl+ (interr. da terminale) perror("signal"), exit(1);if (signal(SIGHUP, sig_hand) == SIG_ERR) //>Terminale del proc. chiuso perror("signal"), exit(1);Il gestore ha il seguente corpo:static void sig_hand(int signo){ #if VERBOSE printf("Server closing ...n"); #endif exit(0); //>Esegue exit_log} 19
  21. 21. Avendo preventivamente registrato un exit handler che effettua le operazioni di log su file, si ottiene il risultato che, alloccorrenza dei segnali sopra riportati, prima della terminazione del server, viene effettuato il log. Si riportano di seguito due frammenti di codice riguardanti la registrazione dellexit handler ed il corpo della funzione registrata: ... if (atexit(exit_log) != 0) //>Registrazione Exit handler perror("atexit(exit_log"), exit(1); ... ... static void exit_log(void){ char buffer[MAX_BUFFER]; getTime(buffer); //>Data/ora chiusura server strcat(buffer, "tSERVER CLOSEnn"); //>Intestazione logging(buffer); //>Log su file #if VERBOSE printf("Server close.n"); #endif } ... Per quanto riguarda la gestione del timer delle partite si è fatto uso del segnale SIGUSR1. Si consideri il seguente scenario esplicativo: – un “clientA” è nello stato “visibile” (le informazioni del clientA sono presenti nella coda dei client pronti); – un “clientB” effettua una richiesta STARTGAME_REQ al server seguita dallid del clientA (richiesta di iniziare la partita con il “clientA”). – sia “clientControllerA” il thread che gestisce la “FASE I” della comunicazione con il “clientA”; – sia “clientControllerB” il thread che gestisce la “FASE I” della comunicazione con il “clientB”. Al momento della ricezione della richiesta STARTGAME_REQ e dellid del clientA, il thread “clientControllerB” estrae dalla coda dei client pronti le informazioni del clientA1. Quindi, leggendo della struttura dati del clientA il tid del “clientControllerA”, lo termina: ... static struct clientData *estraiClient_StopThred(int i){ struct clientData *infoClientTmp = NULL; /*! ENTRY SECTION !*/ if (pthread_mutex_lock(clientReadyMutexQueue->mutex)) //>Chiude il mutex associato alla coda perror("mutex_lock"), exit(1); /*! SEZIONE CRITICA !*/ //>Se esiste un client con ID i lo rimuove dalla coda e termina i lthread clientReadyMutexQueue->queue = removeElementByKey( clientReadyMutexQueue->queue, i, &infoClientTmp); if (infoClientTmp != NULL) pthread_cancel(infoClientTmp->ctrlTid); /*! FINE SEZIONE CRITICA !*/ /*! EXIT SECTION !*/ //>Apre il mutex associato alla coda1 Si suppone che al momento in cui il clientControllerB accede alla coda dei client pronti il clientA sia ancora pr esente in essa. 20
  22. 22. if (pthread_mutex_unlock(clientReadyMutexQueue->mutex)) perror("mutex_unlock"), exit(1); return (infoClientTmp);}La terminazione del “clientControllerA” viene effettuata allinterno dellastessa sezione critica nella quale si esegue lestrazione dalla coda delclientA per evitare “incongruenze” dovute alla possibilità che il clientAha di modificare il suo stato di “visibilità”.Dopo aver inviato la conferma al “clientB”, il “clientControllerB” avvia unthread (“playController”) per gestire la “FASE II” della comunicazione.Dopo la creazione del thread, il “clientControllerB” attende un numero disecondi pari al timer impostato, quindi, invia un segnale SIGUSR1 al thread“playController” creato.In caso di terminazione della partita prima dello scadere del timer, ilthread “playController” termina “clientControllerB”.Di seguito si riportano due frammenti di codice relativi al“clientController” e alla funzione registrata (in “/server/src/server.c”)per il segnale SIGUSR1:...in clientController:...//>Crea nuovo thread per gestire la partita tra i due clientpthread_create(&i, NULL, playController, players);pthread_detach(i); //>Non interessa valore duscita del thread (distaccamento thread)sleep(timer); //>Attende timer secondipthread_kill(i, SIGUSR1); //>Invia il segnale sigusr1 al thread che gestisce la partita......gestore per SIGUSR1:void timeOut(int signo){ if (signo == SIGUSR1){ //>Assegnazione puntatore alla TSD int *stopGameP = (int *) pthread_getspecific(stopGameKey); //>Aggiornamento valore *stopGameP = 1; }}...Come si può osservare dal codice sopra riportato, il gestore di segnaliimposta il valore di un ThreadSpecificData (di key: “stopGameKey”) ad “1”.Prima della richiesta di ogni servizio, il “playController” effettua untest sul valore del TSD al fine di verificare se il timer per la partita èscaduto:...in playController:if (*stopGameP){ //>Se è impostata la flag di fine partita if (request(player1->c_sfd, ENDGAME_REQ)){ //>Richiesta servizio player1: fine partita if (request(player2->c_sfd, ENDGAME_REQ)){ freeAndExit(player1, 0); freeAndExit(player2, 1); } freeAndRestart(player1, player2, tid); } request(player2->c_sfd, ENDGAME_REQ); //>Richiesta servizio player2: fine partita restart(player1, player2); //>Avvia due threads per gestire la connessione con i client}... 21
  23. 23. 4.3 Client: una primitiva fuori programma, lI/O multiplexing Durante la fase di progettazione dellapplicazione è nata la necessità di poter controllare la disponibilità di informazioni su due file descriptor contemporaneamente. Tale necessità si è posta quando è stata affrontata la gestione, lato client, della “visibilità” (sez. 3.1). Inizialmente si era deciso di non consentire ai client la richiesta di servizi durante questo periodo di tempo ma, una tale “soluzione” avrebbe comportato limpossibilità per il client stesso di “cambiare idea”. In poche parole non sarebbe stato possibile il passaggio da “visibilità” ad “invisibilità” (con tutto ciò che questo ne comporta1). Dare la possibilità al client di attendere un avversario e contemporaneamente poter richiedere servizi al server si traduce nella necessità di poter controllare, contemporaneamente, in lettura il file descriptor STDIN_FILENO (per le richieste di servizi dellutente) ed il socket file descriptor sul quale si svolge la comunicazione con il server. Una possibile soluzione sarebbe stata quella di adottare la tecnica del polling aprendo i due descrittori in modalità O_NONBLOCK. Tale soluzione, oltre ad influenzare tutte le altre operazioni di I/O che sono state strutturate per descrittori aperti in modalità bloccante, è comunemente ricordata per la sua inefficienza: gran parte dei cicli di CPU sono inutilmente impegnati per system call che spesso falliscono (dati non disponibili). La scelta è quindi caduta sullI/O multiplexing che consente di controllare più file descriptor contemporaneamente, di bloccare il processo (attesa passiva) se non è possibile effettuare le operazioni richieste e di riprendere lesecuzione quando è possibile effettuare almeno una delle operazioni richieste. Di seguito viene riportato un frammento di codice che si riferisce alla situazione appena descritta: ...in waitPlayer() - FASI.c: ... //>Aggiunge il socket descriptor allinsieme dei socket da controllare in lettura FD_SET(sfd, &rfdset); //>Aggiunge lo stdin descriptor allinsieme FD_SET(STDIN_FILENO, &rfdset); //>Aspetta per operazioni di lettura select(maxfd, &rfdset, NULL, NULL, NULL); //>Pronto a leggere da stdin if (FD_ISSET(STDIN_FILENO, &rfdset)){ ... operazioni di lettura da stdin e gestione richieste servizi ... } //>Pronto a leggere da sfd if (FD_ISSET(sfd, &rfdset)){ ... operazioni di lettura da socket descriptor ... } ... 4.4 Note: possibili miglioramenti In questa sezione vengono annotate alcune possibili modifiche al fine di migliorare le caratteristiche del pacchetto software realizzato. (1) In riferimento alla sez. 3.1: sollevare il client dalla responsabilità di inviare richieste1 Questa limitazione avrebbe impedito qualunque richiesta da parte del client. 22
  24. 24. implicite di INVISIBLE_REQ quando si trova nello stato di "visibilità" e richiede servizi al server. Possibile soluzione: aggiungere alla struttura dati che il server mantiene per ogni client una variabile “flag” che codifica gli stati di “visibilità”/”invisibilità”. In questo modo si può anche scegliere di mantenere in coda tutti i client collegati riconoscendo quelli in attesa di avversario (“visibili”) dal valore della flag.(2) In riferimento alla sez. 4.1: ridefinire la coda dei client pronti, della libreria “/server/src/lib/clientQueue/clientQueue.h”, in maniera che le funzioni definite per la sua gestione prevedano laccesso in mutua esclusione. Possibile soluzione: portare la definizione del mutex associato alla coda allinterno della definizione della coda stessa. Dotare le funzioni per la manipolazione della coda di una “entry section”, “sezione critica” ed “exit section”. Aggiungere una funzione di creazione di una nuova coda contenente tutte le istruzioni di allocazione necessarie.(3) Imporre un limite di tempo massimo per la scelta delle coordinate di sparo per lutente “di turno”. Possibile soluzione: lo scopo è “facilmente” raggiungibile tramite luso del segnale SIGALRM.(4) Consentire ad un utente di ritornare al menu principale durante una partita. Probabilmente una possibile soluzione richiederebbe luso dellI/O multiplexing o del polling.(5) Mostrare agli utenti lo scorrere del timer della partita e del timer relativo definito al punto (3). Possibile soluzione: creare due thread che, in maniera concorrente ed in mutua esclusione, “ogni secondo”, scrivono i valori dei timer su stdout.(6) In riferimento alla sez. 4.2: eliminare il TSD stopGameKey (flag per fine timer) e rendere "coppiaInfoClient" TDS in modo che il gestore del segnale SIGUSR1 invii lui stesso le richieste ai due client di fine partita ed avvii due thread "clientController" per gestirli.(7)In riferimento alla gestione della richiesta di RCVPLAYERS_REQ (sez.3.1) modificare la funzione “inviaClientPronti” definita in “/server/src/lib/threadStartFunctions/threadSF.h” in modo che la chiamata “bloccante” di scrittura sul socket descriptor sia posta allesterno della sezione critica. 23
  25. 25. 5 Codice sorgente./client/src:client.c - file sorgente con funzione main per il clientMakefile - make file per compilare/installare/disinst. il client./client/src/lib:FASI.c - sorgente contenente le funzioni per la gestione delle varie fasi di comunicazione con il serverFASI.h - header file contenente i prototipi delle funzioni implementate in FASI.csocketTools.c - sorgente contenente alcune funzioni per lI/O su socketsocketTools.h - header file dei prototipi delle funzioni implementate in socketTools.c./server/src:compileMode.sh - script di shell bash per la compilazione del server con specifica di modalità: “silent” o “verbose”Makefile - make file per la compilazione/installazione/disinstallazione del serverserver.c - file sorgente contenente la funzione main del server./server/src/lib/clientQueue:clientQueue.c - implementazione funzioni per la coda “dei client pronti”clientQueue.h - dichiarazione funzioni implementate in “clientQueue.c”./server/src/lib/threadStartFunctions:threadSF.c - file sorgente contenente limplementazione delle funzioni di avvio dei threads ed alcune funzioni accessoriethreadSF.h - file header contenente la dichiarazione delle funzioni implementate in threadSF.c ed alcune macro per le varie fasi di comunicazione con i client./server/src/lib/threadStartFunctions/socketIOLib:socketIOLib.c - file sorgente contenente limplementazione di alcune funzioni per lI/O su socketsocketIOLib.h - header file contenente i prototipi delle funzioni implementate in socketIOLib.c 24
  26. 26. c Indice Codice Sorgente es tnecc/l mni/e .lr .vbe/ niaio : n/lgtp Ccalta/ei T/ TNa/lh/l E Ptaaoo/f /* K mcenr )ECE(ss arkoC 0RONtC neci> ,S,Fcd c sa/ TS_ks eotee ;AKTAof kpoz/ M_Ie= nP )ien ;E0ne i ail Ln(m n"u e (( g ele/ ENke e imc" )M,t a i _*O lns> NA(e lli/ x,im cS p ora>l/_;tl"s ctr(e n)Ir caai _ar lea/t 1,goi iNrrR t"sr ndhig G)xIoi aeiaC ( ra mdec/ i ig ono e Int>R=aeGnf (d+/E=h,Si )sdts/)I)*Tla ir.zr RSdi,tr /diVv/ [a_cu ‘Tsae ;sdjt ‘Es/S gad,i ‘irr> rnat ‘lre/ diki *ibdr v_gsn dN;ti c is /‘ {rhr(t ‘‘ ]rcnm ‘ ‘ *‘ ‘/ )acann mN‘‘‘‘‘(‘‘‘‘‘ a‘‘‘‘‘><‘‘‘‘‘ n‘‘‘‘‘)‘‘‘‘‘/ c‘‘‘‘‘ ‘‘‘‘‘ >‘‘ e‘‘‘‘‘‘A‘‘‘‘‘ k‘‘‘‘‘N‘‘‘‘‘ i‘‘‘‘‘ r‘‘‘‘‘‘IN i * o‘‘‘‘‘‘ME r‘‘‘ c e/ e/ eS t‘fo‘‘ _ pd‘‘‘‘ E i/t>‘ eesNm g;nce ae t‘‘‘‘h a‘‘‘‘‘‘ iesovv‘ a‘‘‘‘‘‘ s]Mai A‘‘‘‘‘‘‘‘ hnaia ieoka i gne i‘‘‘‘‘‘ iodc b‘e i‘ bn ‘‘l‘‘‘‘‘‘l‘l‘ ‘sicSin‘lgfNN ‘‘‘‘‘‘‘o‘AnE ‘‘‘"‘‘‘l‘‘rT ‘‘‘‘":‘‘‘l‘O ‘‘‘.‘‘‘‘‘‘t * ‘kInrdt‘;‘* ‘Feu‘uns * h‘‘‘‘‘‘‘‘* ‘ tcoL[r /‘‘‘‘‘‘‘‘‘‘‘‘ n‘‘l‘_:* n‘‘ t‘ gii‘‘ ‘‘ ‘tae* ‘ ‘‘ ‘‘ onhv* *‘‘‘ ‘sdira ‘‘‘‘‘‘‘‘‘‘‘‘ls ‘‘‘‘‘‘‘‘‘‘‘‘‘ ‘‘‘‘‘‘‘‘‘‘‘‘‘ ‘‘‘‘‘‘‘‘‘(‘‘‘ ‘‘‘‘‘‘‘;‘‘‘‘‘ ‘‘‘‘‘‘‘)‘‘‘‘‘ i‘‘‘/ ‘x gdi pa necet soH ar‘* iit r‘‘‘‘‘‘‘‘l‘‘< ‘6 n‘‘‘‘‘‘‘‘d/ t‘‘‘‘‘‘‘‘‘‘‘( /o‘‘‘‘‘‘‘‘‘‘‘* ;‘‘‘‘‘‘‘‘‘‘‘n ‘*tp [ > )‘‘‘‘‘‘‘‘‘‘‘2 ‘‘i ‘t_ ‘_ *p1,__‘e ) a vhor e sspp eag‘ie eev ztivgcnies ips ggrri‘cn m,zlcn o‘aoaa iz*tarrat‘vt d‘ivr‘t‘odia‘"goI edpeni* ai3,acdtni* ze‘eitr‘c ‘‘‘‘‘‘]‘‘‘‘‘‘s ‘‘‘‘‘‘‘‘‘‘‘‘‘ ‘‘‘‘‘‘‘r‘l‘‘‘ ‘‘‘‘‘‘‘l‘‘"‘‘ ‘‘‘‘‘‘r‘r(‘‘‘ ‘‘‘‘‘‘‘‘‘‘r‘‘ tuin‘*ea‘af*eeSs a2ut‘‘‘‘it oi eir tar i /‘‘‘‘‘‘‘l‘‘l>/ ‘‘‘l‘‘irgzres ‘‘‘‘‘‘‘‘l"‘e ‘:‘‘‘‘‘‘‘l‘‘V ‘‘‘‘‘‘‘‘‘‘‘‘< ‘‘‘‘‘(‘‘‘"‘‘* ‘‘idrnvd‘ccI *‘ain)‘‘‘‘‘‘r o‘‘"lsi/ ‘) g‘rcecz * s)e aao o‘‘ltpn ( c‘‘iisn/ b1 ifvian deeg F i>a i‘ileeo noriuio‘‘‘ oranFpr‘‘‘ usnz/oS‘‘ eno> A‘# treiut(‘‘ somP .<n i"ro>iP‘‘* mce bd# ai d / d/ / leir t<ln t .. /e ecu .. d >yl .t r m/ ssd#/ >eu / hnc ."c > .nd# i "Fei<n hfl lei / Iiu > htei psl <cc n _ _ee ./u ..esr >ye naIF i ennaio ia/d o)nyli/ n ntne a aeoOlP htd axia pyl n oetOi l rt,zih/ # iuri <c i)a> u /e))tbIn/ >dd# nonrnfdt .<c iioiorrS .sl nd sh.,pr(a/ htu otirrnzS bei dsdr(ba> iei erdz.d/ i moitdn l aiiizn d f// io lnvl,u_t >sl (.f(nsn/ o n co> h<c tic >gd ndG .nl gd/ e n or/ ad ei/ / n st/ en knG /yu i.t/ isd# aee kiu est htu l,s etd cro >tsl cs nnei .ee .nei no>hl<c1,tncii,l>>csl/ tns .s8i elk/ho<c ii/ tie# 7 0# 0/ 2 6
  27. 27. c Indice Codice Sorgente ecc/Nimni/eesia tnl/l .lr zb ataaoo/f [ rogtp /l pvae: nzo tcalta/ei v oia/lh/ oai/ 2dn esi> ras rtep )rnl rho/ vdi ( g> )_zia ziat} dotI [rb= sio )itho ;enzt_ zaooe int ;n/tr [r tgtap )uzf0lrl1(iti )btfme>ei>up} r(lurnvd],(i ef,bsdr;;((s fodofe)rane fee]loodeon r,i s]pN=t ii_ / _** _ee xèeedr(t mozR1rnuLDufh amdl]aytzr=ii nom/r.beth=b _rrnrrtgr[(s ai>r"beui(( eonvet]l6oa a;vma(sN=/ nrle1(l)rLer een/ > mdtu),nhrirnf eiio)easEDEfi eeof;gvooh.rs gdLs_ td²sr[n __np)fpe a_Rhfuc a,S²r_ eafNRofa eafti hhiy_non [m;TTer ze / looirds"eUan do/iesnoto_ ngosodiAI_ onul()yto)rrs inlzind h nesèeai*Lse 0r)tco [o>otf vh/srp ]iL)[ai <5]rl ["a0evh o0r<xn pa{](i mo1;i eo 0 v t N) "( ,re1gff nar/g")lsUi o o]agtc:f tro/vn,;hSsn e#t;r>nr|S"r mon);t>np:! igl>0)r0si.(i "a ) R%(p Ret t t Yn O%(e !lNc}= 3xi g rl n_e)s n e=_n( /o6‘sedwUreor ‘p1pe)eneOet ‘‘‘enrrLvsrc {*t*d‘oLr*r( )‘‘vieosoae> ‘‘ir_eaNsmv/ ‘t_tmdz_inrs t‘CeoOurp{u/ ‘_ _nkofae *‘‘r2urtrntht ;ssEisp tr _a pRP(p T"r iEOff uu aISr )/ / S /‘‘‘‘‘]‘‘l‘‘‘s ‘‘‘‘‘‘[‘,‘‘‘‘ ‘‘‘,‘‘‘r‘‘‘‘‘ ‘‘‘‘‘‘‘‘‘‘‘‘( ‘‘‘‘l‘r‘r(‘‘‘ ‘‘‘‘‘,‘l‘‘r‘* a3‘a‘ae‘‘t ctcocaiat ol‘cno‘i sgugidtt aiie<v nnnlt1 >i‘e‘h‘‘g‘a ecz‘tt‘cm d< svnoeS‘‘ *‘‘uor‘*e‘v‘>/ pi mo zear _/ ai/al ap)l iFtII} t/ii (_ rp t>"" iil;E* a> p/ e t‘/ tr ir I )S (A I )A (F e A )* Si (} h _ ;S a) AOIw ,stdae/IUDF ).n.ti*ZM1/ rd.dt ECCE d)_ NI{F ddn ONIl _pd_ =ross ( aiasndoc"r e_n (p )_ar(h"sdnt );sr(,:tef dfiaon%eon drson:tCi od_t% n( E C ;p i or )(d& 1,nr ,0)rd_r)rdTp r!rsrndtt*c ar.sa cu(oi _anae ;xc"e oa "cr )sti,sdstfn* drizd)at,cO d)sid*kcsnf .ndot oeeeC ds__ s/N/ d_a (tN _d_ ()no __ rso%te .s _ ( _d i . nd .I _ ;.sn__nnp )ss*d&c" )r(,.uti ,_ 6% C tih_TAme pn .: g a";:inn sntFlad d&sNgff _ti.s=ar /or.nnoi(i r(a)r(rrt pr(tE,,sr sta1(yad /riavcvaaor a_ sgneig zl ioi zs aa n i =SI niatd .f/ eraro)_adnvlp eedii ecV ctr)nddzzesr seet,sdlig<* orotGddzi/0e kue*sr(aidzd/ i/ a ri c it"s . t")r n 1,co* e ()ori2tapro>ti ;x*((// cl )ekrf f 8 0 07 2 6
  28. 28. cctaaoo/f Indice Codice Sorgenteni//Na/lh/lesegtpei tnvbe/ .lrcalta/ : c iaio el/l m r usc > WS )etih H t ouk C ne fs lo D od/ n_ow} gi oTft nud nndo i RUd ‘‘‘‘‘‘‘‘;ss(u ‘‘;‘.‘‘{;n,(seit oi ‘()‘.‘‘c"oi)p ‘‘‘,.: ‘)sn1 ‘‘‘"‘‘ otss( ‘‘i‘‘ incnn ‘s‘%i ginDi ‘‘o ).n;r ‘/g eRt"h_nx xf ncfv oe di it sdD‘a *peln‘nsnshsn < 2 ) c‘‘‘(‘"( cr‘‘‘‘i .soi‘i‘r n‘)‘‘‘‘* e‘‘‘‘‘ts t(‘‘‘‘(p7 8t3/‘‘‘‘)‘l‘‘‘‘‘c//0 0 2 ioniae>/6
  29. 29. Indice Codice Sorgenteeictaaoo/fMel/alta/eiesegtp /l knNa/lh/ a//vbe: frcl io l iam . a ****c**aoio ***e**vt)zr ***n e*tclh #**in*aapi"@a"mz #****o**donf@# a oiL ***e tiemuc * be *:ea*e a**l***a$ml #*****hbcc*"@c i o* C ******t(in*on **r***r$rhih* ******P*s*(** ****t"nrr*uca ***t*)****P** i******zb‰: ***a*s*i**e n***cilPPr i*n*iotle a**r*** m*:** t***** )*l.****** c*oniE s*$****** t*e****# t* A e/*iN # O******** j***p***** lk******* Onoa jPaln / a j"))oc etPai i$io l/O maozee elelo tT(f$Peo P)b;cnkh hoOhbnl"@ a$natidv tT( /$sc iiijbam fbbb(sthbb(@ ; f/nrn])j‰v ) )ob)hnbIm ctaiat$ ;$P(n$ ii;fbohbb(s@ adctijc is lst$ tOf POv tb)lm P)(($$(@ i(n)if ipts)((!@ #**isn(zanff #h(*;nrn]szoiosat[ *t$i)i]e/ndf **ilib$u)i‰i *a"ui(krhb!@ *Pir"$ntt$[ *nnt)kn;a$[ *o"ade)i‰i * zheinhb i ethiiP e inmoao"@ i:znnc zahi i a uie l #**acnbhh(!@ n*apebiu osnPiloI e*oiipntist e*ee iaeo s ae d****n*ec:n icbea uC #****u*eedzo*i #**.r********* ****.tr*r***l# ***l*t******* ***l********* *l*t*vlr**l** *l*tv*l***l** a***tascniha ***a***ic*l ****s*eei* # *** i b***e*crt s*tde *t oceailt o*lzst e**t * o*ntd )rrorlear # t*fo*r*N*# TonT Sl*oA O*()*cl:*** j)l‰s*l**** Tsc*k*$**s e$c**c*** s*$*(**o# e*tlLI lsoL Htr**c)** T*oogS lk*(cs**** e lk*e** e)o‰:oc b aosrTs lo d$cbt$ oot T )e dooeoo setl(O ( TSkjk ji es)$‰$c loO$cfc oTioS$c otsei g ejfr( TlaHs l lob()a‰ #**c*)kci)a)a *n*r)jc)sr(O ******o**i:s #*c*n$s*$*l:n$ #***b*sb(r***(O ****cb*sa s i **‰*bos*f $f *O*(*( *oSj*oaz *t$*il*iocfb$ *t*O*aa #O*)Ot*** Sj( **(***(k$*c**# ****s*$***()* *****k*sjn$j* ***)*c)*)(*b* ***j(*j(c***c *******S**e n i z*fg iv nbe n* p e)ac eO$ dsc ei i ******* *i ****f*i *l *****i*O* *****t*t* ******d c:i .ib se* # oto lki o*= .Tt st/ oc* ocl ee ob t** # To= /a i* h**=oll .*bb*# oc*** os**c ebS* odoc t**t /e* l*bO o*sj** ll skc** Tsc=o ib lk.seAoo FT /t Soc Ili .Ht=s IsS Alse Foa /Tf Sik hrTs ie da li be .sH obr Sls=o Aoa Fas /b Iik =k cntO i e Sf ics Of ijc ***** .cn ***** ncl ***** erc * * #****s clt ee nji #*****o t=e si* t.i i* ebl #******i in=i ******* ihb *****dc bt ******* la *****i /P ****** .n #************* *************# ************* ****f******** ************* **eea*e*# n**o* #*****r******* aia e**** T***r**** I****zD L*ace** C**oen *******i*ne** E*im*** ezomiM dpppi opcek *************# ****l******** *****l******* ************* ************* ********* N*rr**f**1#*********f*** e******* M*l****/ a******/ ei***l*** kl*****# f**r**** l******* 8# 0 27 0# 6

×