diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/.vscode/settings.json b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/.vscode/settings.json new file mode 100644 index 00000000..a8e19269 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.associations": { + "cstdlib": "c", + "*.tcc": "c", + "memory": "c", + "new": "c", + "array": "c", + "string": "c", + "string_view": "c" + } +} \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/.vscode/tasks.json b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/.vscode/tasks.json new file mode 100644 index 00000000..df74fa09 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: gcc compila il file attivo", + "command": "/usr/bin/gcc", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Attività generata dal debugger." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/Documentazione_Zingrillo.pdf b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/Documentazione_Zingrillo.pdf new file mode 100644 index 00000000..332465a6 Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/Documentazione_Zingrillo.pdf differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/Makefile b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/Makefile new file mode 100644 index 00000000..0df51c52 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/Makefile @@ -0,0 +1,35 @@ +# Variabili +CC = gcc +CFLAGS = -Wall +LDFLAGS = + +# File sorgente +SERVER_SOURCES = server.c modules/quiz.c modules/game.c modules/common.c modules/database.c modules/dashboard.c +CLIENT_SOURCES = client.c modules/common.c + +# File oggetto +SERVER_OBJECTS = $(SERVER_SOURCES:.c=.o) +CLIENT_OBJECTS = $(CLIENT_SOURCES:.c=.o) + +# Eseguibili +SERVER_EXECUTABLE = server +CLIENT_EXECUTABLE = client + +# Regola per costruire tutto +all: $(SERVER_EXECUTABLE) $(CLIENT_EXECUTABLE) + +# Regola per costruire il server +$(SERVER_EXECUTABLE): $(SERVER_OBJECTS) + $(CC) $(LDFLAGS) -o $@ $^ + +# Regola per costruire il client +$(CLIENT_EXECUTABLE): $(CLIENT_OBJECTS) + $(CC) $(LDFLAGS) -o $@ $^ + +# Regola per costruire i file oggetto +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +# Regola per pulire i file generati +clean: + rm -f $(SERVER_OBJECTS) $(CLIENT_OBJECTS) $(SERVER_EXECUTABLE) $(CLIENT_EXECUTABLE) \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client new file mode 100644 index 00000000..df37077e Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client.c b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client.c new file mode 100644 index 00000000..7ede0587 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client.c @@ -0,0 +1,326 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "include/common.h" +#include "include/params.h" + +// Funzione che previene il comportamento standard in caso di SIGPIPE, che termina il processo. +// Viene stampato un messaggio di errore e si permette al gestore degli errori di send di gestire l'errore. +void handle_sigpipe(int sig) +{ + printf("Connessione chiusa dal server\n"); +} + +// Funzione che stampa il messaggio di benvenuto +void stampaMenu() +{ + printf("Menù:\n"); + printf("1 - Comincia una sessione di Trivia\n"); + printf("2 - Esci\n"); + printplus(); +} + +// Funzione che gestisce l'interfaccia iniziale del client +bool menuIniziale() +{ + int scelta = 0; + int ret = 0; + do + { + intro(); + stampaMenu(); + printf("\nLa tua scelta: "); + ret = scanf("%d", &scelta); + // Pulisco il buffer di input per gestire il caso in cui l'utente abbia inserito + // input non numerici + while (getchar() != '\n') + ; + if (ret != 1 || (scelta != 1 && scelta != 2)) + { + printf("\nScelta non valida\n\n"); + } + else if (scelta == 2) + { + return false; + } + } while (scelta != 1); + return true; +} + +// Funzione che gestisce l'interfaccia per la scelta del nickname +void scegliNickname(int sd) +{ + char buffer[TEXTLEN], ok[TEXTLEN]; + intro(); + while (1) + { + printf("Inserisci il tuo nickname (max %d caratteri): ", TEXTLEN - 1); + // Leggo il nickname da tastiera + if (fgets(buffer, sizeof(buffer), stdin) != NULL) + { + size_t len = strlen(buffer); + // Rimuovo il carattere di nuova linea se presente + if (len > 0 && buffer[len - 1] == '\n') + { + buffer[len - 1] = '\0'; + len--; + } + else + { + // Se non c'è un carattere di nuova linea, allora l'input è stato troncato + // e devo svuotare il buffer di input + int ch; + while ((ch = getchar()) != '\n' && ch != EOF) + ; + printf("Errore: il nickname supera la lunghezza massima di %d caratteri\n", TEXTLEN - 1); + continue; + } + + // Controllo se l'input è vuoto + if (len == 0) + { + printf("Errore: il nickname non può essere vuoto\n"); + continue; + } + + break; // Esco dal ciclo se il nickname è stato letto correttamente + } + else + { + printf("Errore durante la lettura dell'input\n"); + } + } + inviaMsg(buffer, sd, false); // Invio il nickname al server + riceviMsg(ok, sd, false); // Ricevo la risposta del server + if (strcmp(ok, "1") == 0) + { + printf("\nNickname accettato\n\n"); + } + else if (strcmp(ok, "0") == 0) + { + printf("\nNickname rifiutato\n\n"); + scegliNickname(sd); + } + else + { + printf("Errore durante la ricezione della risposta del server\n"); + exit(EXIT_FAILURE); + } +} +// Funzione che mostra la classifica +void mostraClassifica(int sd) +{ + int num_temi; + char bufferOut[TEXTLEN]; + riceviMsg(bufferOut, sd, false); // Ricevo il numero di temi + num_temi = atoi(bufferOut); + printf("\n"); + intro(); + for (int k = 0; k < num_temi; k++) + { + int num_partecipanti; + riceviMsg(bufferOut, sd, false); // Ricevo il numero di partecipanti + num_partecipanti = atoi(bufferOut); + printf("Punteggio tema %d\n", k + 1); + for (int j = 0; j < num_partecipanti; j++) + { + int punteggio; + riceviMsg(bufferOut, sd, false); // Ricevo il nickname + punteggio = atoi(bufferOut); + riceviMsg(bufferOut, sd, false); // Ricevo il punteggio + printf("- %s %d\n", bufferOut, punteggio); + } + printf("\n"); + } +} + +// Funzione che gestisce l'interfaccia per la scelta del quiz +// Restituisce false se non ci sono quiz disponibili, true altrimenti +bool scegliQuiz(int sd, char *nomeQuiz) +{ + // Recupero i quiz dal server + char buffer[TEXTLEN]; + int numQuiz, scelta = 0, ret = 0; + riceviMsg(buffer, sd, false); // Ricevo il numero di quiz disponibili + numQuiz = atoi(buffer); + if (numQuiz == 0) + { + printf("Non ci sono quiz disponibili\n"); + return false; + } + char *nomiTemi[numQuiz]; + printf("Quiz disponibili:\n"); + printplus(); + printf("\n"); + for (int i = 1; i <= numQuiz; i++) // Ricevo i nomi dei quiz + { + riceviMsg(buffer, sd, false); + nomiTemi[i - 1] = (char *)malloc((strlen(buffer) + 1) * sizeof(char)); + gestisciErroriMalloc(nomiTemi[i - 1]); + strcpy(nomiTemi[i - 1], buffer); + printf("%d - %s\n", i, buffer); + } + + printplus(); + printf("\n"); + do { + char buffer[TEXTLEN]; + printf("La tua scelta: "); + if (fgets(buffer, sizeof(buffer), stdin) != NULL) { + // Rimuovo il carattere di nuova linea se presente + size_t len = strlen(buffer); + if (len > 0 && buffer[len - 1] == '\n') { + buffer[len - 1] = '\0'; + } + + // Controllo se l'input è ENDQUIZ o SHOWSCORE + if (strcmp(buffer, FINEQUIZ) == 0) { + printf("Quiz terminato.\n"); + inviaMsg(buffer, sd, false); + return false; + } else if (strcmp(buffer, MOSTRAPUNTEGGIO) == 0) { + inviaMsg(buffer, sd, false); + mostraClassifica(sd); + continue; + } + + // Converto l'input in un numero + ret = sscanf(buffer, "%d", &scelta); + if (ret != 1 || scelta < 1 || scelta > numQuiz) { + printf("Scelta non valida\n"); + } + } else { + printf("Errore durante la lettura dell'input\n"); + } +} while (scelta < 1 || scelta > numQuiz); + sprintf(buffer, "%d", scelta); + inviaMsg(buffer, sd, false); // Invio la scelta al server + strcpy(nomeQuiz, nomiTemi[scelta - 1]); // Salvo il nome del quiz scelto + for(int i=0; i 0 && bufferOut[len - 1] == '\n') + { + bufferOut[len - 1] = '\0'; + len--; + } + else + { + // Se non c'è un carattere di nuova linea, allora l'input è stato troncato + // e devo svuotare il buffer di input + int ch; + while ((ch = getchar()) != '\n' && ch != EOF) + ; + printf("Errore: il messaggio supera la lunghezza massima di %d caratteri\n", TEXTLEN - 1); + continue; + } + + // Controllo se l'input è vuoto + if (len == 0) + { + printf("Errore: il messaggio non può essere vuoto\n"); + continue; + } + + break; // Esco dal ciclo se il messaggio è stato letto correttamente + } + + inviaMsg(bufferOut, sd, false); // Invio la risposta al server + if (strcmp(bufferOut, FINEQUIZ) == 0) + { + printf("Quiz terminato.\n"); + return false; + } + if (strcmp(bufferOut, MOSTRAPUNTEGGIO) == 0) + { + i--; // Decremento i in modo che la prossima iterazione mostri la domanda corrente + mostraClassifica(sd); + continue; + } + riceviMsg(bufferOut, sd, false); // Ricevo la valutazione della risposta + ok = strcmp(bufferOut, "1") == 0; + if (ok) + { + printf("\nRisposta corretta\n\n"); + } + else + { + printf("\nRisposta errata\n\n"); + } + } + return true; +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + printf("Client lanciato in modo errato.\nUtilizzo corretto: ./client \n"); + exit(EXIT_FAILURE); + } + signal(SIGPIPE, handle_sigpipe); + while (menuIniziale()) + { + char nomeQuiz[TEXTLEN]; + int ret, sd; + struct sockaddr_in server_address; + sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd == -1) + { + perror("Errore durante la creazione del socket"); + exit(EXIT_FAILURE); + } + // inizializzo la struttura per la connessione al server + server_address.sin_family = AF_INET; + server_address.sin_port = htons(atoi(argv[1])); + inet_pton(AF_INET, SERVER_IP, &server_address.sin_addr); + // mi connetto al server + ret = connect(sd, (struct sockaddr *)&server_address, sizeof(server_address)); + // controllo se la connessione è andata a buon fine + if (ret == -1) + { + perror("Errore durante la connessione al server"); + exit(EXIT_FAILURE); + } + scegliNickname(sd); + while (scegliQuiz(sd, nomeQuiz) && giocaQuiz(sd, nomeQuiz)) + ; + close(sd); // chiudo la connessione con il server + } + return 0; +} diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client.o b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client.o new file mode 100644 index 00000000..a2d1102d Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/client.o differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/common.h b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/common.h new file mode 100644 index 00000000..6026c53c --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/common.h @@ -0,0 +1,8 @@ +// Funzioni che possono essere utilizzate sia dal client che dal server +// per ridurre il codice duplicato + +void intro(); +void printplus(); +void inviaMsg(char *, int, bool); +void riceviMsg(char *, int, bool); +void gestisciErroriMalloc(void *); \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/dashboard.h b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/dashboard.h new file mode 100644 index 00000000..50ccf932 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/dashboard.h @@ -0,0 +1 @@ +void *pannelloDiControllo(void *); \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/database.h b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/database.h new file mode 100644 index 00000000..1b2ec84e --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/database.h @@ -0,0 +1,72 @@ +#include "quiz.h" +#include +#include + +// Strutture dati e funzioni finalizzati a contenere i dati degli utenti e a gestire le operazioni su di essi + +struct punteggioTema +{ + bool completato; // true se il tema è stato completato dall'utente, false altrimenti + bool giocato; // true se l'utente ha giocato il tema, false altrimenti + int punteggio; // punteggio ottenuto dall'utente nel tema +}; + +// Struttura dati per l'albero binario di ricerca degli utenti +// Ordinato per nickname alfabeticamente +struct utente +{ + char nickname[TEXTLEN]; // nickname dell'utente + struct punteggioTema *punteggioTemi; + struct utente *left; // puntatore al figlio sinistro nell'albero binario di ricerca + struct utente *right; // puntatore al figlio destro nell'albero binario di ricerca +}; + +// Struttura dati per l'albero binario di ricerca dei punteggi +// Ordinato per punteggio decrescente e, in caso di parità, per nickname alfabeticamente +struct punteggio +{ + struct utente *giocatore; // utente a cui è associato il punteggio + int punti; // punteggio ottenuto dall'utente + struct punteggio *left; // puntatore al figlio sinistro nell'albero binario di ricerca + struct punteggio *right; // puntatore al figlio destro nell'albero binario di ricerca +}; +struct utenti +{ + struct utente *root; // radice dell'albero binario di ricerca + pthread_mutex_t mutex; // mutex per la mutua esclusione + int numUtenti; // numero di utenti registrati +}; +struct classifica +{ + struct punteggio **vettorePunteggi; // vettore di punteggi per ogni tema + int *vettorePartecipanti; // vettore con il numero di partecipanti per ogni tema + int *vettoreCompletati; // vettore con il numero di utenti che hanno completato il tema + pthread_mutex_t *vettoreMutex; // vettore di mutex per la mutua esclusione +}; +// Struttura dati da passare al thread che gestisce la connessione con un client +struct game +{ + struct quiz *q; // quiz + struct utenti *players; // utenti + struct classifica *classifica; // classifica + int socket; // socket +}; + +// Struttura dati da passare al thread che gestisce il pannello di controllo +struct datiPdC +{ + struct utenti *players; // utenti + struct classifica *score; // classifica + struct quiz *q; // quiz +}; + +void inserisciUtente(struct utenti *, struct utente *); +bool controllaNickname(char *, struct utenti *); +struct punteggio *creaPunteggio(struct utente *, int); +void inserisciInClassifica(struct classifica *, struct utente *, int, int); +void eliminaDaClassifica(struct classifica *, char *, int, int); +void eliminaTuttiPunteggi(struct classifica *, struct utente *, int); +struct utente *eliminaUtente(struct utente *, char *nickname, int, struct classifica *); +void eliminaDaDB(struct utenti *, char *, int, struct classifica *); +void svuotaDBMutex(struct utenti *); +void svuotaClassifica(struct classifica *, int); diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/game.h b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/game.h new file mode 100644 index 00000000..886904c8 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/game.h @@ -0,0 +1,2 @@ +void *partita(void *); +void *pannelloDiControllo(void *); \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/params.h b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/params.h new file mode 100644 index 00000000..5a808127 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/params.h @@ -0,0 +1,11 @@ +#define TEXTLEN 256 // Lunghezza massima di un messaggio +#define THEMESIZE 5 // Numero di domande per ogni tema +#define QUIZFILENAMELEN 10 // Lunghezza massima del nome del file del quiz +#define PORT 3000 // Usata anche da altre applicazioni, come React e NodeJS, ma non le includiamo in questo progetto +#define SERVER_IP "127.0.0.1" +#define BACKLOG 20 // Numero massimo di connessioni in attesa di essere gestite +#define NUMPLUS 50 // Numero di caratteri '+' da stampare nei messaggi client +#define FINEQUIZ "endquiz" // Comando per terminare il quiz +#define MOSTRAPUNTEGGIO "show score" // Comando per visualizzare il punteggio +#define UPDATETIME 3 // Tempo di aggiornamento del pannello di controllo +#define CONNECTION_CLOSED 2 // Codice di errore per la chiusura della connessione \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/quiz.h b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/quiz.h new file mode 100644 index 00000000..cdb5f782 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/include/quiz.h @@ -0,0 +1,34 @@ +#include "params.h" +#include + +// Struttura dati per le risposte, organizzate in una lista +struct risposta +{ + char testo[TEXTLEN]; // Testo della risposta + struct risposta *next; // Puntatore alla risposta successiva +}; + +// Struttura dati per le domande, organizzate in un array statico +struct domanda +{ + char testo[TEXTLEN]; // Testo della domanda + struct risposta risposte; // Risposte della domanda +}; + +// Struttura dati per i temi, organizzati in un array dinamico +struct tema +{ + char nome[TEXTLEN]; // Nome del tema + struct domanda domande[THEMESIZE]; // Domande del tema +}; + +struct quiz +{ + int n_temi; // Numero di temi, dinamico perché deciso al momento del parsing + struct tema *temi; // Temi del quiz +}; + +void parse(struct quiz *); +bool rispostaCorretta(struct domanda *, char *); +void listaTemi(struct quiz *); +void eliminazioneQuiz(struct quiz *); \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/common.c b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/common.c new file mode 100644 index 00000000..779e466d --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/common.c @@ -0,0 +1,108 @@ +// Modulo di utilità in comune tra client e server + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/params.h" +#include "../include/common.h" + +// Funzione di utilità che stampa un numero di caratteri '+' pari a NUMPLUS +void printplus() +{ + for (int i = 0; i < NUMPLUS; i++) + printf("+"); +} + +// Funzione di utilità che stampa il messaggio di benvenuto +void intro() +{ + printf("Trivia Quiz\n"); + printplus(); + printf("\n"); +} + +// Funzione di utilità che gestisce gli errori di invio +void gestisciErroriSend(int ret, int len, int sd, bool callFromThread) +{ + if (ret != len) + { + // Se la connessione è stata chiusa dall'altro host, chiudo la connessione e termino il thread o il processo + if (ret == -1 && (errno == EPIPE || errno == ECONNRESET)) + { + close(sd); + callFromThread ? pthread_exit(NULL) : exit(CONNECTION_CLOSED); + } + else + { + // Altrimenti, stampo un messaggio di errore e termino il processo (nel caso di un thread server, l'intero processo) + perror("Errore durante l'invio del messaggio"); + exit(EXIT_FAILURE); + } + } +} + +// Funzione di utilità che invia un messaggio al socket sd +// Il parametro callFromThread è true se la funzione è chiamata da un thread, false altrimenti +void inviaMsg(char *msg, int sd, bool callFromThread) +{ + uint32_t lenNet; // utilizzo un tipo certificato per la lunghezza del messaggio + int len, ret; + // invio la lunghezza del messaggio, non comprensiva del carattere di terminazione + len = strlen(msg); + lenNet = htonl(len); // converto la lunghezza in formato network + ret = send(sd, &lenNet, sizeof(u_int32_t), 0); + gestisciErroriSend(ret, sizeof(u_int32_t), sd, callFromThread); + // invio il messaggio + ret = send(sd, msg, len, 0); + gestisciErroriSend(ret, len, sd, callFromThread); +} + +// Funzione di utilità che gestisce gli errori di ricezione +void gestisciErroriRecv(int ret, int len, bool callFromThread, int sd) +{ + // Se la connessione è stata chiusa dall'altro host, chiudo la connessione e termino il thread o il processo + if (!ret) + { + printf("La connessione è stata chiusa\n"); + close(sd); + callFromThread ? pthread_exit(NULL) : exit(CONNECTION_CLOSED); + } + // Altrimenti, stampo un messaggio di errore e termino il processo (nel caso di un thread server, l'intero processo) + else if (ret != len) + { + perror("Errore durante la ricezione del messaggio"); + close(sd); + exit(EXIT_FAILURE); + } +} +// Funzione di utilità che riceve un messaggio dal socket sd +// Il parametro callFromThread è true se la funzione è chiamata da un thread, false altrimenti +void riceviMsg(char *msg, int sd, bool callFromThread) +{ + int ret; + uint32_t len; // utilizzo un tipo certificato per la lunghezza del messaggio + // ricevo la lunghezza del messaggio + ret = recv(sd, &len, sizeof(uint32_t), 0); + len = ntohl(len); // converto la lunghezza in formato host + gestisciErroriRecv(ret, sizeof(uint32_t), callFromThread, sd); + // ricevo il messaggio + ret = recv(sd, msg, len, 0); + gestisciErroriRecv(ret, len, callFromThread, sd); + // aggiungo il carattere di terminazione della stringa + msg[len] = '\0'; +} + +// Funzione di utilità che gestisce gli errori di allocazione della memoria +void gestisciErroriMalloc(void *ptr) +{ + if (ptr == NULL) + { + perror("Errore durante l'allocazione della memoria"); + exit(EXIT_FAILURE); + } +} \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/common.o b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/common.o new file mode 100644 index 00000000..ebddcc5a Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/common.o differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/dashboard.c b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/dashboard.c new file mode 100644 index 00000000..4931fe17 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/dashboard.c @@ -0,0 +1,117 @@ +// Modulo server finalizzato alla gestione del pannello di controllo + +#include "../include/dashboard.h" +#include "../include/database.h" +#include +#include +#include +#include +#include + +// Funzione che stampa i punteggi di un utente, facendo una visita in-order dell'albero binario di ricerca +void stampaPunteggi(struct punteggio *root) +{ + if (root != NULL) + { + stampaPunteggi(root->left); + printf("- %s %d\n", root->giocatore->nickname, root->punti); + stampaPunteggi(root->right); + } +} +// Funzione che stampa gli utenti, facendo una visita in-order dell'albero binario di ricerca +void stampaUtente(struct utente *root) +{ + if (root != NULL) + { + stampaUtente(root->left); + printf("- %s\n", root->nickname); + stampaUtente(root->right); + } +} + +// Funzione che prende il lock sul mutex degli utenti e invoca stampaUtente +void stampaPartecipanti(struct utenti *players) +{ + pthread_mutex_lock(&players->mutex); + printf("Partecipanti (%d)\n", players->numUtenti); + stampaUtente(players->root); + pthread_mutex_unlock(&players->mutex); +} + +// Funzione che stampa gli utenti che hanno completato un tema, facendo una visita in-order dell'albero binario di ricerca +void stampaCompletatiTema(struct utente *root, int tema) +{ + if (root != NULL) + { + stampaCompletatiTema(root->left, tema); + if (root->punteggioTemi[tema].completato) + printf("- %s\n", root->nickname); + stampaCompletatiTema(root->right, tema); + } +} + +// Funzione che prende il lock sul mutex degli utenti e invoca stampaCompletatiTema +void stampaCompletati(struct utenti *players, int num_temi, struct classifica *score) +{ + pthread_mutex_lock(&players->mutex); + for (int i = 0; i < num_temi; i++) + { + printf("Quiz Tema %d completato\n", i + 1); + if (score->vettoreCompletati[i]) + stampaCompletatiTema(players->root, i); + else + printf("------\n"); + printf("\n"); + } + pthread_mutex_unlock(&players->mutex); +} + +// Funzione che prende il lock sul mutex di ogni tema e invoca stampaPunteggi +void stampaClassifica(struct classifica *score, int num_temi) +{ + for (int i = 0; i < num_temi; i++) + { + pthread_mutex_lock(score->vettoreMutex + i); + printf("Punteggio tema %d\n", i + 1); + stampaPunteggi(score->vettorePunteggi[i]); + printf("\n"); + pthread_mutex_unlock(score->vettoreMutex + i); + } +} + +// Funzione che gestisce il pannello di controllo del server +void *pannelloDiControllo(void *dati) +{ + // recupero i dati passati al thread + struct datiPdC *datiConvertiti = (struct datiPdC *)dati; + struct utenti *players = datiConvertiti->players; + struct classifica *score = datiConvertiti->score; + struct quiz *q = datiConvertiti->q; + + listaTemi(q); // Stampo i temi + stampaPartecipanti(players); // Stampo i partecipanti + printf("\n"); + stampaClassifica(score, q->n_temi); // Stampo la classifica + stampaCompletati(players, q->n_temi, score); // Stampo gli utenti che hanno completato un tema + printf("Premere 'q' seguito da invio per terminare il server\n"); + sleep(UPDATETIME); // Attendo UPDATETIME secondi + char buffer[3]; // Se viene digitato 'q' seguito da invio, il server termina + if (fgets(buffer, sizeof(buffer), stdin) != NULL) + { + if (buffer[0] == 'q' && buffer[1] == '\n') + { + printf("Terminazione del server...\n"); + svuotaDBMutex(players); // Svuoto il database utenti + svuotaClassifica(score, q->n_temi); // Svuoto la classifica + eliminazioneQuiz(q); // Elimino il quiz + free(dati); // Libero la memoria allocata per la struttura dati + exit(EXIT_SUCCESS); + } + } + printf("Pulisco lo schermo\n"); // Pulisco lo schermo + system("clear"); // Pulisco lo schermo + + fflush(stdout); // Svuoto il buffer di output + pannelloDiControllo(dati); // Richiamo ricorsivamente la funzione + return NULL; +} diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/dashboard.o b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/dashboard.o new file mode 100644 index 00000000..be3d3ac2 Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/dashboard.o differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/database.c b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/database.c new file mode 100644 index 00000000..3a3c9b92 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/database.c @@ -0,0 +1,299 @@ +// Modulo server finalizzato alla gestione dei dati degli utenti e della classifica + +#include "../include/database.h" +#include "../include/game.h" +#include "../include/common.h" +#include +#include +#include + +// Funzione che inserisce un utente nell'albero binario di ricerca +void inserisciUtente(struct utenti *players, struct utente *new) +{ + pthread_mutex_lock(&players->mutex); + struct utente **current = &players->root; + while (*current != NULL) + { + if (strcmp(new->nickname, (*current)->nickname) < 0) + { + current = &(*current)->left; + } + else + { + current = &(*current)->right; + } + } + *current = new; + players->numUtenti++; // Incremento il numero di utenti registrati + pthread_mutex_unlock(&players->mutex); +} + +// Funzione che controlla se un nickname è già presente nell'albero binario di ricerca +bool controllaNickname(char *nickname, struct utenti *players) +{ + struct utente *p = players->root; + int res; + while (p != NULL) + { + res = strcmp(nickname, p->nickname); + if (res < 0) + p = p->left; + else if (res > 0) + p = p->right; + else + return false; + } + return true; +} + +// Funzione che crea un nuovo nodo per l'albero binario di ricerca dei punteggi +struct punteggio *creaPunteggio(struct utente *player, int punti) +{ + struct punteggio *newNode = (struct punteggio *)malloc(sizeof(struct punteggio)); + gestisciErroriMalloc(newNode); + newNode->giocatore = player; + newNode->punti = punti; + newNode->left = NULL; + newNode->right = NULL; + return newNode; +} + +// Funzione che inserisce un punteggio nell'albero binario di ricerca +struct punteggio *inserisciPunteggio(struct punteggio *root, struct utente *player, int punti) +{ + // Se l'albero è vuoto, crea un nuovo nodo come radice + if (root == NULL) + { + return creaPunteggio(player, punti); + } + // Scorro l'albero per trovare la posizione appropriata + if (punti > root->punti || (punti == root->punti && strcmp(player->nickname, root->giocatore->nickname) < 0)) + { + // Inserisco nel sottoalbero sinistro + root->left = inserisciPunteggio(root->left, player, punti); + } + else + { + // Inserisco nel sottoalbero destro + root->right = inserisciPunteggio(root->right, player, punti); + } + + return root; +} + +// Funzione che inserisce un punteggio nella classifica +void inserisciInClassifica(struct classifica *score, struct utente *player, int punteggio, int quizScelto) +{ + pthread_mutex_lock(score->vettoreMutex + quizScelto - 1); + struct punteggio *p = score->vettorePunteggi[quizScelto - 1]; + score->vettorePartecipanti[quizScelto - 1]++; + if (p == NULL) + { + score->vettorePunteggi[quizScelto - 1] = creaPunteggio(player, punteggio); + pthread_mutex_unlock(score->vettoreMutex + quizScelto - 1); + return; + } + inserisciPunteggio(p, player, punteggio); + pthread_mutex_unlock(score->vettoreMutex + quizScelto - 1); +} + +// Funzione che trova il punteggio minimo nell'albero binario di ricerca +// Utilizzata per eliminare un nodo con due figli +struct punteggio *trovaPunteggioMinimo(struct punteggio *root) +{ + while (root && root->left != NULL) + { + root = root->left; + } + return root; +} + +// Funzione che trova l'utente con nickname alfabeticamente minimo nell'albero binario di ricerca +// Utilizzata per eliminare un nodo con due figli +struct utente *trovaUtenteMinimo(struct utente *root) +{ + while (root && root->left != NULL) + { + root = root->left; + } + return root; +} + +// Funzione che elimina un nodo dall'albero binario di ricerca +struct punteggio *eliminaPunteggio(struct punteggio *root, char *nickname, int punteggio) +{ + + if (root == NULL) + { + return root; // Albero vuoto + } + + // Cercare il nodo da eliminare + if ((punteggio > root->punti) || (punteggio == root->punti && strcmp(nickname, root->giocatore->nickname) < 0)) + { + root->left = eliminaPunteggio(root->left, nickname, punteggio); + } + else if ((punteggio < root->punti) || (punteggio == root->punti && strcmp(nickname, root->giocatore->nickname) > 0)) + { + root->right = eliminaPunteggio(root->right, nickname, punteggio); + } + else + { + // Nodo trovato + // Caso 1: Nessun figlio o un solo figlio + if (root->left == NULL) + { + struct punteggio *temp = root->right; + free(root); + return temp; + } + else if (root->right == NULL) + { + struct punteggio *temp = root->left; + free(root); + return temp; + } + + // Caso 2: Due figli + struct punteggio *temp = trovaPunteggioMinimo(root->right); // Successore in ordine + root->giocatore = temp->giocatore; // Copia i dati del successore + root->punti = temp->punti; + root->right = eliminaPunteggio(root->right, nickname, punteggio); // Elimina il successore + } + return root; +} + +// Funzione che elimina un punteggio dalla classifica, prendendo il lock sul mutex del tema e chiamando eliminaPunteggio +void eliminaDaClassifica(struct classifica *score, char *nickname, int punteggio, int quizScelto) +{ + pthread_mutex_lock(score->vettoreMutex + quizScelto - 1); + struct punteggio *root = score->vettorePunteggi[quizScelto - 1]; + score->vettorePartecipanti[quizScelto - 1]--; + score->vettorePunteggi[quizScelto - 1] = eliminaPunteggio(root, nickname, punteggio); + pthread_mutex_unlock(score->vettoreMutex + quizScelto - 1); +} + +// Funzione che elimina tutti i punteggi di un utente dalla classifica +void eliminaTuttiPunteggi(struct classifica *score, struct utente *player, int num_temi) +{ + for (int i = 0; i < num_temi; i++) + { + if (!player->punteggioTemi[i].giocato) + { + continue; + } + eliminaDaClassifica(score, player->nickname, player->punteggioTemi[i].punteggio, i + 1); + } +} + +// Funzione che decrementa il numero di utenti che hanno completato un tema +// in fase di eliminazione di un utente +void rimuoviDaiCompletati(struct classifica *score, struct utente *player, int num_temi) +{ + for (int i = 0; i < num_temi; i++) + { + if (player->punteggioTemi[i].completato) + { + score->vettoreCompletati[i]--; + } + } +} + +// Funzione che elimina un utente dall'albero binario di ricerca +struct utente *eliminaUtente(struct utente *root, char *nickname, int num_temi, struct classifica *score) +{ + if (root == NULL) + { + return root; // Albero vuoto + } + + // Cerco il nodo da eliminare + if (strcmp(nickname, root->nickname) < 0) + { + root->left = eliminaUtente(root->left, nickname, num_temi, score); + } + else if (strcmp(nickname, root->nickname) > 0) + { + root->right = eliminaUtente(root->right, nickname, num_temi, score); + } + else + { + // Nodo trovato + + // Caso 1: Nessun figlio o un solo figlio + if (root->left == NULL) + { + struct utente *temp = root->right; + rimuoviDaiCompletati(score, root, num_temi); + free(root); + return temp; + } + else if (root->right == NULL) + { + struct utente *temp = root->left; + rimuoviDaiCompletati(score, root, num_temi); + free(root); + return temp; + } + + // Caso 2: Due figli + struct utente *temp = trovaUtenteMinimo(root->right); // Successore in ordine + strcpy(root->nickname, temp->nickname); // Copio i dati del successore + root->right = eliminaUtente(root->right, nickname, num_temi, score); // Elimino il successore + } + return root; +} + +// Funzione che elimina un utente dal database, prendendo il lock sul mutex degli utenti e chiamando eliminaUtente +void eliminaDaDB(struct utenti *db, char *nickname, int num_temi, struct classifica *score) +{ + pthread_mutex_lock(&db->mutex); + struct utente *root = db->root; + db->root = eliminaUtente(root, nickname, num_temi, score); + db->numUtenti--; + pthread_mutex_unlock(&db->mutex); +} + + + +// Funzione che svuota l'albero binario di ricerca degli utenti +void svuotaDB(struct utente*root){ + if(root==NULL){ + return; + } + svuotaDB(root->left); + svuotaDB(root->right); + free(root->punteggioTemi); + free(root); +} + +// Funzione che svuota il database, prendendo il lock sul mutex +void svuotaDBMutex(struct utenti *db){ + pthread_mutex_lock(&db->mutex); + svuotaDB(db->root); + pthread_mutex_unlock(&db->mutex); + free(db); +} +// Funzione che svuota l'albero binario di ricerca dei punteggi +void svuotaClassificaTema(struct punteggio *root){ + if(root==NULL){ + return; + } + svuotaClassificaTema(root->left); + svuotaClassificaTema(root->right); + free(root); +} + +// Funzione che svuota la classifica, prendendo il lock sul mutex +void svuotaClassifica(struct classifica *score, int num_temi){ + for(int i=0; ivettoreMutex+i); + svuotaClassificaTema(score->vettorePunteggi[i]); + pthread_mutex_unlock(score->vettoreMutex+i); + } + free(score->vettorePunteggi); + free(score->vettorePartecipanti); + free(score->vettoreCompletati); + free(score->vettoreMutex); + free(score); +} \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/database.o b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/database.o new file mode 100644 index 00000000..8c5fcb2c Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/database.o differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/game.c b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/game.c new file mode 100644 index 00000000..9f632be3 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/game.c @@ -0,0 +1,209 @@ +// Modulo server finalizzato alla gestione del gioco di un client +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/database.h" +#include "../include/game.h" +#include "../include/common.h" + +// Funzione che registra un utente, controllando che il nickname non sia già presente +// e ritornando un puntatore all'utente registrato +struct utente *registraUtente(int socket, struct utenti *players, int num_temi) +{ + char nickname[TEXTLEN]; + bool ok; + do + { + riceviMsg(nickname, socket, true); // Ricevo il nickname + ok = controllaNickname(nickname, players); // Controllo se il nickname è già presente + inviaMsg(ok ? "1" : "0", socket, true); // Invio il risultato del controllo + } while (!ok); + // Inizialiizzo il nuovo utente + struct utente *new = (struct utente *)malloc(sizeof(struct utente)); + gestisciErroriMalloc(new); + strcpy(new->nickname, nickname); + new->left = NULL; + new->right = NULL; + new->punteggioTemi = (struct punteggioTema *)malloc(num_temi * sizeof(struct punteggioTema)); + gestisciErroriMalloc(new->punteggioTemi); + for (int i = 0; i < num_temi; i++) + { + new->punteggioTemi[i].completato = false; + new->punteggioTemi[i].giocato = false; + new->punteggioTemi[i].punteggio = 0; + } + // Inserisco il nuovo utente nell'albero binario di ricerca + inserisciUtente(players, new); + return new; +} + +// Funzione che invia all'utente i punteggi relativi a un tema, facendo una visita in-order dell'albero binario di ricerca +void inviaPunteggi(struct punteggio *root, int socket) +{ + if (root != NULL) + { + char buffer[TEXTLEN]; + inviaPunteggi(root->left, socket); + sprintf(buffer, "%d", root->punti); + inviaMsg(buffer, socket, true); // Invio il punteggio + sprintf(buffer, "%s", root->giocatore->nickname); + inviaMsg(buffer, socket, true); // Invio il nickname + inviaPunteggi(root->right, socket); + } +} + +// Funzione che invia tutti i punteggi relativi ai temi giocati +void inviaTuttiiPunteggi(struct classifica *score, int socket, int num_temi) +{ + char buffer[TEXTLEN]; + sprintf(buffer, "%d", num_temi); + inviaMsg(buffer, socket, true); // Invio il numero di temi + for (int i = 0; i < num_temi; i++) + { + // prendo il lock sul mutex del tema + pthread_mutex_lock(score->vettoreMutex + i); + sprintf(buffer, "%d", score->vettorePartecipanti[i]); + // invio il numero di partecipanti + inviaMsg(buffer, socket, true); + inviaPunteggi(score->vettorePunteggi[i], socket); + // rilascio il lock + pthread_mutex_unlock(score->vettoreMutex + i); + } +} + +// Funzione che gestisce la scelta del quiz da parte dell'utente, ritornando il quiz scelto +int proponiQuiz(int socket, struct quiz *q, struct utente *player, struct classifica *score, struct utenti *players) +{ + char buffer[TEXTLEN]; + int scelta, num_temi_disp = 0; + // num_temi_disp è il numero di temi non ancora giocati + for (int i = 0; i < q->n_temi; i++) + { + if (!player->punteggioTemi[i].giocato) + num_temi_disp++; + } + // Manteniamo la corrispondenza tra la numerazione dei temi non giocati e quella dei temi + int *corrispondenze = (int *)malloc(num_temi_disp * sizeof(int)); + gestisciErroriMalloc(corrispondenze); + sprintf(buffer, "%d", num_temi_disp); + inviaMsg(buffer, socket, true); // Invio il numero di temi non ancora giocati + if (num_temi_disp == 0) + { // Se non ci sono temi disponibili l'utente viene eliminato e la connessione chiusa + eliminaTuttiPunteggi(score, player, q->n_temi); + eliminaDaDB(players, player->nickname, q->n_temi, score); + close(socket); + return 0; + } + int ultima_corrispondenza = 0; + // Invio i temi non ancora giocati + for (int i = 0; i < q->n_temi; i++) + { + if (player->punteggioTemi[i].giocato) + continue; + strcpy(buffer, q->temi[i].nome); + inviaMsg(buffer, socket, true); + corrispondenze[ultima_corrispondenza] = i; + ultima_corrispondenza++; + } + // Ricevo la scelta dell'utente + riceviMsg(buffer, socket, true); + while (true) + { + if (strcmp(buffer, FINEQUIZ) == 0) + { + eliminaTuttiPunteggi(score, player, q->n_temi); + eliminaDaDB(players, player->nickname, q->n_temi, score); + close(socket); + return 0; + } + if (strcmp(buffer, MOSTRAPUNTEGGIO) == 0) + { + inviaTuttiiPunteggi(score, socket, q->n_temi); + riceviMsg(buffer, socket, true); + continue; + } + scelta = atoi(buffer); + // Controllo lato server che la scelta sia valida + if (scelta < 1 || scelta > num_temi_disp) + { + printf("Scelta non valida\n"); + exit(EXIT_FAILURE); + } + break; + } + + // Aggiorno le strutture dati + scelta = corrispondenze[scelta - 1] + 1; + player->punteggioTemi[scelta - 1].giocato = true; + return scelta; +} + + + +// Funzione che gestisce il quiz, ritornando true se l'utente decide di continuare, false altrimenti +bool gestisciQuiz(int socket, struct quiz *q, int quizScelto, struct utente *player, struct classifica *score, struct utenti *players) +{ + char buffer[TEXTLEN]; + int punteggio = 0; + bool correct; + // Inserisco in classifica l'utente con punteggio 0 + inserisciInClassifica(score, player, punteggio, quizScelto); + for (int i = 0; i < THEMESIZE; i++) + { + strcpy(buffer, q->temi[quizScelto - 1].domande[i].testo); + inviaMsg(buffer, socket, true); // Invio la domanda + riceviMsg(buffer, socket, true); // Ricevo la risposta + if (strcmp(buffer, FINEQUIZ) == 0) + { // Se l'utente decide di uscire dal quiz + eliminaTuttiPunteggi(score, player, q->n_temi); // Elimino tutti i punteggi dell'utente + eliminaDaDB(players, player->nickname, q->n_temi, score); // Elimino l'utente dal database + close(socket); // Chiudo la connessione + return false; + } + if (strcmp(buffer, MOSTRAPUNTEGGIO) == 0) + { // Se l'utente chiede di visualizzare i punteggi + inviaTuttiiPunteggi(score, socket, q->n_temi); // Invio i punteggi + i--; // Decremento i in modo che la prossima iterazione mostri la domanda corrente + } + else + { + correct = rispostaCorretta(&q->temi[quizScelto - 1].domande[i], buffer); // Controllo se la risposta è corretta + inviaMsg(correct ? "1" : "0", socket, true); // Invio il risultato + if (correct) + { // Se la risposta è corretta, aggiorno coerentemente le strutture dati + eliminaDaClassifica(score, player->nickname, punteggio, quizScelto); + punteggio++; + player->punteggioTemi[quizScelto - 1].punteggio = punteggio; + inserisciInClassifica(score, player, punteggio, quizScelto); + } + } + } + // Se l'utente ha completato il quiz, aggiorno le strutture dati + player->punteggioTemi[quizScelto - 1].completato = true; + score->vettoreCompletati[quizScelto - 1]++; + return true; +} + +void *partita(void *game) +{ + int quizScelto; + struct utente *player; + // recupero i dati passati al thread + int client_socket = ((struct game *)game)->socket; + struct utenti *players = ((struct game *)game)->players; + struct classifica *score = ((struct game *)game)->classifica; + struct quiz *q = ((struct game *)game)->q; + int num_temi = q->n_temi; + // Registro l'utente + player = registraUtente(client_socket, players, num_temi); + // Finché l'utente decide di continuare il quiz e ci sono temi disponibili, propongo un quiz e gestisco le risposte + while ((quizScelto = proponiQuiz(client_socket, q, player, score, players)) && gestisciQuiz(client_socket, q, quizScelto, player, score, players)) + ; + pthread_exit(NULL); +} \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/game.o b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/game.o new file mode 100644 index 00000000..8407cae2 Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/game.o differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/quiz.c b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/quiz.c new file mode 100644 index 00000000..9080f31e --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/quiz.c @@ -0,0 +1,168 @@ +// Modulo server per la gestione del quiz +#include +#include +#include +#include +#include +#include +#include + +#include "../include/quiz.h" +#include "../include/common.h" +#include "../include/params.h" + +// Funzione di utilità utilizzata nel parsing +// Legge un file, inserendo il contenuto in un buffer, fino a un carattere terminatore +// Prende in input il buffer, il file descriptor, la posizione di partenza, il carattere terminatore e un puntatore a intero +// Ritorna la lunghezza del buffer +// Supporta due modalità: se il puntatore a intero è NULL, legge fino al carattere terminatore +// Se il puntatore a intero è diverso da NULL, legge fino al carattere terminatore o al carattere '\n' e ritorna, +// tramite il puntatore a intero, 1 se il primo carattere è il terminatore, 0 altrimenti +int readUntil(char *buffer, int fd, int start, char terminator, bool *cause) +{ + char *pointer = buffer; + lseek(fd, start, SEEK_SET); // sposta il cursore alla posizione start + while (read(fd, pointer, 1) > 0 && *(pointer) != terminator && (*pointer != '\n' || cause == NULL)) + pointer++; + if (cause != NULL) + *cause = *(pointer) == terminator ? 1 : 0; + *(pointer) = '\0'; + return pointer - buffer + 1 + start; +} + +// Funzione di utilità per convertire una stringa in minuscolo +// Utilizzata per confrontare le risposte +void toLowerCase(char *str) +{ + while (*str) + { + *str = tolower((unsigned char)*str); + str++; + } +} + +// Funzione per visualizzare la lista dei temi +void listaTemi(struct quiz *q) +{ + intro(); + printf("Temi:\n"); + for (int i = 0; i < q->n_temi; i++) + printf("%d - %s\n", i + 1, q->temi[i].nome); + printplus(); + printf("\n\n"); +} + +// Funzione per verificare se una risposta è corretta +bool rispostaCorretta(struct domanda *d, char *risposta) +{ + struct risposta *r; + toLowerCase(risposta); + r = &d->risposte; + while (r != NULL) + { // scorro la lista di risposte + if (strcmp(r->testo, risposta) == 0) + return true; + r = r->next; + } + return false; +} + +// Funzione per il parsing dei quiz +// Note sul formato dei quiz: +// - Ogni tema è contenuto in un file .quiz +// - Il file indice.quiz contiene il numero di temi e il nome di ciascun tema +// - Ogni domanda termina con un carattere '|' +// - Le risposte sono separate da caratteri '~' +void parse(struct quiz *q) +{ + int indice; + char buffer[TEXTLEN]; + int indexcursor = 0, numtemi; + // mi posiziono nella cartella quiz + if (chdir("quiz") != 0) + { + perror("Si è verificato un errore durante il cambio di directory"); + exit(EXIT_FAILURE); + } + // apro il file indice + indice = open("indice.quiz", O_RDONLY); + if (indice == -1) + { + perror("Si è verificato un errore durante l'apertura del file indice.quiz"); + exit(EXIT_FAILURE); + } + // leggo la prima riga del file indice, che contiene il numero di temi + indexcursor = readUntil(buffer, indice, indexcursor, '\n', NULL); + numtemi = atoi(buffer); + // istanzio le necessarie strutture dati + q->n_temi = numtemi; + q->temi = (struct tema *)malloc(numtemi * sizeof(struct tema)); + gestisciErroriMalloc(q->temi); + for (int i = 0; i < numtemi; i++) + { // per ogni tema + char stringa_file_tema[QUIZFILENAMELEN]; + int file_tema; + sprintf(stringa_file_tema, "%d.quiz", i + 1); // ricavo il nome del file tema + file_tema = open(stringa_file_tema, O_RDONLY); + if (file_tema == -1) + { + perror("Si è verificato un errore durante l'apertura dei file di quiz"); + exit(EXIT_FAILURE); + } + int themecursor = 0; + struct tema t; + indexcursor = readUntil(buffer, indice, indexcursor, '\n', NULL); // leggo il nome del tema dal file indice + strcpy(t.nome, buffer); + for (int j = 0; j < THEMESIZE; j++) + { // per ogni domanda + themecursor = readUntil(buffer, file_tema, themecursor, '|', NULL); // leggo il testo della domanda + struct domanda d; + struct risposta *r; + bool cause = 1; + strcpy(d.testo, buffer); + r = &d.risposte; + while (cause) + { // Scorro le risposte + themecursor = readUntil(buffer, file_tema, themecursor, '~', &cause); + strcpy(r->testo, buffer); + if (cause) + { + r->next = (struct risposta *)malloc(sizeof(struct risposta)); + gestisciErroriMalloc(r->next); + r = r->next; + } + else + { + r->next = NULL; + } + } + t.domande[j] = d; + } + q->temi[i] = t; + close(file_tema); + } + close(indice); +} +// Funzione per eliminare un quiz +void eliminazioneQuiz(struct quiz *q) +{ + for (int i = 0; i < q->n_temi; i++) + { + struct tema t = q->temi[i]; + for (int j = 0; j < THEMESIZE; j++) + { + struct domanda d = t.domande[j]; + struct risposta *r = &d.risposte; + bool primaRisposta = true; + while (r != NULL) + { + struct risposta *temp = r; + r = r->next; + if (!primaRisposta) + free(temp); + primaRisposta = false; + } + } + } + free(q->temi); +} diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/quiz.o b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/quiz.o new file mode 100644 index 00000000..09956000 Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/modules/quiz.o differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/1.quiz b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/1.quiz new file mode 100644 index 00000000..f9d79a51 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/1.quiz @@ -0,0 +1,5 @@ +Chi ha scritto la "Divina Commedia"?|dante alighieri~dante +Qual è il titolo dell'opera di Giovanni Boccaccio che racconta storie di dieci giovani durante la peste nera?|decameron~il decameron~il decamerone~decamerone +Quale poeta è noto per il suo "Canzoniere", una raccolta di poesie dedicate a Laura?|francesco petrarca~petrarca +In quale città è ambientata la maggior parte delle novelle del "Decameron"?|firenze +Chi è l'autore del "De vulgari eloquentia"?|dante alighieri~dante diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/2.quiz b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/2.quiz new file mode 100644 index 00000000..e8b0b358 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/2.quiz @@ -0,0 +1,5 @@ +In che anno è scoppiata la Prima Guerra Mondiale?|1914 +Chi era il leader dell'Unione Sovietica durante la Seconda Guerra Mondiale?|joseph stalin~stalin~iosif stalin +In che anno furono promulgate le leggi razziali in Italia?|1938 +In che anno è caduto il Muro di Berlino?|1989 +Chi è stato il primo presidente nero degli Stati Uniti?|barack obama~obama diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/3.quiz b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/3.quiz new file mode 100644 index 00000000..8588c448 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/3.quiz @@ -0,0 +1,5 @@ +Chi ha scritto "Critica della ragion pura"?|immanuel kant~kant +Quale filosofo è noto per la frase "Penso, dunque sono"?|rené descartes~cartesio~rene descartes~ descartes +Chi è l'autore del "Tractatus Logico-Philosophicus"?|ludwig wittgenstein~wittgenstein +Quale filosofo ha sviluppato il concetto di "volontà di potenza"?|friedrich nietzsche~nietzsche +Chi ha scritto "Essere e tempo"?|martin heidegger~heidegger diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/4.quiz b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/4.quiz new file mode 100644 index 00000000..b1c549d5 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/4.quiz @@ -0,0 +1,5 @@ +Chi ha sconfitto Annibale nella battaglia di Zama?|scipione l'africano~scipione +Quale riformatore romano è noto per le sue leggi agrarie e la sua morte violenta?|tiberio gracchi~tiberio gracchus~tiberio gracco +In che anno è stata fondata la Repubblica Romana?|509 a.c.~509 +Chi era il primo re di Roma secondo la leggenda?|romolo +Quale generale romano ha attraversato il Rubicone, scatenando una guerra civile?|gaio giulio cesare~giulio cesare~cesare diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/5.quiz b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/5.quiz new file mode 100644 index 00000000..f094718c --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/5.quiz @@ -0,0 +1,5 @@ +Chi ha dipinto "La vocazione di San Matteo"?|caravaggio +Quale architetto ha progettato la piazza di San Pietro a Roma?|gian lorenzo bernini~bernini +Chi ha scolpito "L'Estasi di Santa Teresa"?|gian lorenzo bernini~bernini +Quale pittore barocco è noto per le sue opere drammatiche e l'uso del chiaroscuro?|caravaggio +Chi ha dipinto "Le tre grazie"?|peter paul rubens~rubens~pieter paul rubens diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/6.quiz b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/6.quiz new file mode 100644 index 00000000..5ba010c4 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/6.quiz @@ -0,0 +1,5 @@ +Quale organizzazione internazionale è stata fondata nel 1945 per promuovere la pace e la sicurezza globale?|onu~organizzazione delle nazioni unite +Chi è stato il primo segretario generale delle Nazioni Unite?|trygve lie +Quale trattato ha posto fine alla Prima Guerra Mondiale?|trattato di versailles~versailles~di versailles +Quale paese ha lasciato l'Unione Europea nel 2020?|regno unito~uk +Quale accordo internazionale del 2015 mira a limitare il riscaldamento globale a meno di 2 gradi Celsius rispetto ai livelli preindustriali?|accordo di parigi~di parigi diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/indice.quiz b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/indice.quiz new file mode 100644 index 00000000..c864dc7a --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/quiz/indice.quiz @@ -0,0 +1,7 @@ +6 +Letteratura italiana del Medioevo +Storia del Novecento +Filosofia moderna +Roma Repubblicana +Arte Barocca +Politica Internazionale diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/readme.md b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/readme.md new file mode 100644 index 00000000..86da94ef --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/readme.md @@ -0,0 +1,18 @@ +# Progetto di Reti Informatiche - Giulio Zingrillo - Voto finale 29 +Ho presentato il progetto al primo appello della sessione invernale. +La prof. Righetti è stata molto scrupolosa, aveva letto attentamente il codice e lo aveva sottoposto a molti test. +Nel mio caso aveva trovato due errori, che sono stati corretti nella versione caricata qui e che riporto di seguito: +- Il primo, più serio, riguardava l'invio della lunghezza del messaggio, che, nella fretta, avevo gestito male: infatti io non facevo né la conversione del valore tra host e network, né utilizzavo i tipi "certificati" uint; +- Il secondo riguardava la gestione dell'input utente per le risposte al quiz: avevo gestito il caso in cui l'utente inseriva più caratteri della lunghezza del buffer, ma non quello in cui si limitava a premere invio senza aver scritto nulla. + +La professoressa è stata comunque molto comprensiva: mi ha chiesto, in sede di orale, come avrei corretto gli errori e mi ha fatto modificare il codice. + +I principali punti di forza del progetto, che sono giustificati sinteticamente nella documentazione, sono l'impiego degli alberi binari di ricerca - che garantiscono ottime prestazioni nell'inserimento, eliminazione e stampa ordinata di nodi -, e dei thread, che abbattono l'overhead dovuto ai cambi di contesto. +Un thread, in particolare, è dedicato alla gestione del pannello di controllo, che si aggiorna ogni 3 secondi (ma il parametro è configurabile) e termina automaticamente se l'utente preme q e dà invio. Per capire quando il socket è stato chiuso in fase di invio del messaggio (e, quindi, lato client) ho gestito il segnale SIGPIPE. +Inoltre, ho implementato un formato .quiz basato su caratteri delimitatori e un file di indice. Il parsing dei quiz, effettuato all'avvio del server, è improntato alla flessibilità: aggiungendo file nella cartella quiz e modificando l'indice si possono aggiungere domande e risposte. + +In merito alle scelte di rete, ho inserito nella documentazione un diagramma del progetto come macchina a stati per dimostrare che, sotto opportune condizioni, definire un tipo di messaggio era superfluo: in ogni momento client e server sapevano a priori quale messaggio aspettarsi. + +Eventuali ampliamenti del progetto, che non sono riuscito a implementare per mancanza di tempo, sono l'aggiunta di scambi di messaggi tramite protocolli binari (ad esempio, l'invio della classifica o dei temi) e la gestione della terminazione con Ctrl-C lato client e lato server. + +Il mio consiglio, comunque, è di prestare sempre un occhio al tempo nella realizzazione del progetto: fare un progetto che funziona è fondamentale per accedere all'esame, e farlo bene dà una certa soddisfazione personale, ma dal momento che questa parte è valutata solo 4 punti è opportuno non distrarsi troppo dalla preparazione dell'orale, che ha invece un peso molto maggiore. \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server new file mode 100644 index 00000000..ab83076b Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server.c b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server.c new file mode 100644 index 00000000..2912f098 --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "include/game.h" +#include "include/database.h" +#include "include/params.h" +#include "include/common.h" + +// gestisco il segnale SIGPIPE evitando il comportamento di default +void handle_sigpipe(int sig) {} +// fai notare la modularità dei quiz +// fai notare che hai definito un tuo formato per i quiz +// fai notare lo standard c89 +// fai notare gli alberi binari come strutture dati +// fai notare la gestione dei segnali +// fai notare la gestione dei thread +// il terminatore di stringa non viaggia sulla rete +// parla dei vari moduli del codice +// parla del formato dei quiz che lascia flessibilità nei testi e permette risposte multiple + +int main() +{ + int server_socket, client_socket, ret, n_temi, flags; + struct sockaddr_in server_address; + struct datiPdC *dati; + struct classifica *score; + struct utenti *players; + pthread_t *thread; + struct quiz q; + signal(SIGPIPE, handle_sigpipe); + // effettuo il parsing dei dati dei quiz + parse(&q); + // inizializzo la lista degli utenti + players = (struct utenti *)malloc(sizeof(struct utenti)); + gestisciErroriMalloc(players); + players->root = NULL; + pthread_mutex_init(&players->mutex, NULL); + players->numUtenti = 0; + // inizializzo la classifica + n_temi = q.n_temi; + score = (struct classifica *)malloc(sizeof(struct classifica)); + gestisciErroriMalloc(score); + score->vettorePunteggi = malloc(n_temi * sizeof(struct punteggio)); + gestisciErroriMalloc(score->vettorePunteggi); + score->vettoreMutex = malloc(n_temi * sizeof(pthread_mutex_t)); + gestisciErroriMalloc(score->vettoreMutex); + score->vettorePartecipanti = malloc(n_temi * sizeof(int)); + gestisciErroriMalloc(score->vettorePartecipanti); + score->vettoreCompletati = malloc(n_temi * sizeof(int)); + gestisciErroriMalloc(score->vettoreCompletati); + for (int i = 0; i < n_temi; i++) + { + pthread_mutex_init(score->vettoreMutex + i * sizeof(pthread_mutex_t), NULL); + score->vettorePartecipanti[i] = 0; + score->vettorePunteggi[i] = NULL; + score->vettoreCompletati[i] = 0; + } + // inizializzo la struttura con i dati da passare al thread che gestisce il pannello di controllo + dati = (struct datiPdC *)malloc(sizeof(struct datiPdC)); + gestisciErroriMalloc(dati); + dati->players = players; + dati->score = score; + dati->q = &q; + // configuro stdin per la modalità non bloccante + flags = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); + // creo un thread per il pannello di controllo + thread = (pthread_t *)malloc(sizeof(pthread_t)); + gestisciErroriMalloc(thread); + ret = pthread_create(thread, NULL, pannelloDiControllo, (void *)dati); + if (ret) + { + perror("Errore durante la creazione del thread che gestisce il pannello di controllo"); + exit(EXIT_FAILURE); + } + + // inizializzo il socket + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket == -1) + { + perror("Errore durante la creazione del socket"); + exit(EXIT_FAILURE); + } + // inizializzo la struttura per il server + server_address.sin_family = AF_INET; + server_address.sin_port = htons(PORT); + inet_pton(AF_INET, SERVER_IP, &server_address.sin_addr); + // effettuo il binding del socket + ret = bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)); + if (ret == -1) + { + perror("Errore durante il binding del socket"); + exit(EXIT_FAILURE); + } + ret = listen(server_socket, BACKLOG); + if (ret == -1) + { + perror("Errore durante la listen del socket"); + exit(EXIT_FAILURE); + } + // accetto connessioni + while (1) + { + struct sockaddr_in client_address; + socklen_t client_address_len = sizeof(client_address); + client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len); + if (client_socket == -1) + { + perror("Errore durante la connessione con il client"); + exit(EXIT_FAILURE); + } + + // crea un nuovo thread per ogni client + pthread_t *thread = (pthread_t *)malloc(sizeof(pthread_t)); + gestisciErroriMalloc(thread); + // inizializzo la struct game con i dati da passare al thread + struct game *g = (struct game *)malloc(sizeof(struct game)); + gestisciErroriMalloc(g); + g->q = &q; + g->players = players; + g->classifica = score; + g->socket = client_socket; + ret = pthread_create(thread, NULL, partita, (void *)g); + if (ret) + { + perror("Errore durante la creazione di un nuovo thread"); + exit(EXIT_FAILURE); + } + } + + return 0; +} diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server.o b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server.o new file mode 100644 index 00000000..d94f41b1 Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/server.o differ diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/start.sh b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/start.sh new file mode 100644 index 00000000..5e69a68e --- /dev/null +++ b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/Progetti studenti/A.A.24-25 - Zingrillo/start.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Controllo la presenza di gcc +if ! command -v gcc &> /dev/null +then + echo "Errore: gcc non è installato." + exit 1 +fi + +# Controllo la presenza di make +if ! command -v make &> /dev/null +then + echo "Errore: make non è installato." + exit 1 +fi + +# Lancio il comando make +make + +# Controllo se il comando make è andato a buon fine +if [ $? -ne 0 ]; then + echo "Errore: il comando make è fallito." + exit 1 +fi + +# Apro due nuove finestre del terminale e lancio ./client 3000 +gnome-terminal -- bash -c "./client 3000; exec bash" +gnome-terminal -- bash -c "./client 3000; exec bash" + +# Lancio il comando ./server nella scheda corrente +./server \ No newline at end of file diff --git a/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/progetto2024-2025.pdf b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/progetto2024-2025.pdf new file mode 100644 index 00000000..8318d1be Binary files /dev/null and b/TERZO ANNO/I SEMESTRE/Reti Informatiche/Progetti/progetto2024-2025.pdf differ