 * Le programme crée plusieurs processus, où chaque processus génère des nombres aléatoires à travers plusieurs cycles.
 * Chaque processus utilise une graine unique pour la génération des nombres aléatoires afin d'assurer une distribution différente des valeurs
 * dans chaque processus, évitant ainsi les répétitions et assurant une meilleure répartition des valeurs dans le tableau final.
 * Dans chaque cycle, chaque processus génère un nombre de nombres aléatoires et met à jour un tableau partagé en mémoire inter-processus (IPC)
 * avec les occurrences de chaque nombre généré.
 * Cette mise à jour du tableau IPC se fait de manière synchronisée grâce à l'utilisation de sémaphores,
 * qui garantissent qu'un seul processus accède à la mémoire partagée à la fois.
 * Pour la synchronisation des processus, nous avons choisi d'utiliser une granularité grossière. Cela signifie que l'accès au tableau IPC
 * est verrouillé dans son ensemble pendant que chaque processus effectue ses mises à jour. Bien que cette approche puisse entraîner des temps d'attente
 * plus longs pour les autres processus, elle simplifie la gestion de la synchronisation en évitant les conflits au niveau des éléments individuels du tableau.
 * Les sémaphores sont utilisés pour éviter les conflits d'accès concurrentiel au tableau IPC :
 *   - Avant de modifier le tableau, chaque processus verrouille le sémaphore pour garantir qu'aucun autre processus ne puisse y accéder simultanément.
 *   - Une fois la mise à jour effectuée, le processus déverrouille le sémaphore, permettant ainsi à un autre processus de modifier le tableau en toute sécurité.
 * À la fin de tous les cycles, une fois que chaque processus a mis à jour le tableau IPC avec les occurrences des nombres aléatoires générés,
 * le programme envoie ce tableau au serveur via un socket. Le serveur peut alors traiter ces données, par exemple pour effectuer des analyses
 * ou des traitements supplémentaires sur les occurrences des nombres.



        int *tableau_client_recu = malloc(TAILLE_TABLEAU * sizeof(int));
        if (tableau_client_recu == NULL) {
            log_printf("Erreur ~ |%s| Allocation mémoire échouée pour le tableau client\n", adresse_ip_client);
            exit(EXIT_FAILURE);
        }

        log_printf("Info ~ |%s| Reception du Tableau du client \n", adresse_ip_client);

        if (read(sock_nouveau_client, tableau_client_recu, TAILLE_TABLEAU * sizeof(int)) == -1) {
            log_printf("Erreur ~ |%s| Échec lors de la lecture du tableau du client\n",adresse_ip_client);
            perror("Erreur lors de la lecture");
        }

        log_printf("Succes ~ |%s| Le Tableau du client a ete recu par le serveur\n", adresse_ip_client);

        log_printf("Info ~ |%s| Synchronisation du tableau du client avec le tableau du serveur...\n", adresse_ip_client);

        for (int i = 0; i < TAILLE_TABLEAU; i++) {
            tableau_IPC[i] += tableau_client_recu[i];
        }
        log_printf("Succes ~ |%s| Le Tableau du client a ete synchronisé avec le tableau du serveur\n", adresse_ip_client);

        close(sock_nouveau_client);
        log_printf("Succes ~ |%s| Le client a ete déconnecté du serveur\n", adresse_ip_client);

        free(tableau_client_recu);
        nbrClientTotalTraiter++;

        log_printf("Info ~ %d/%d clients traités - il reste %d client(s) à traiter\n",
              nbrClientTotalTraiter,
              nbrClientPrevus,
              nbrClientPrevus - nbrClientTotalTraiter);


              log_printf("Info ~ Récupération de l'adresse IP du client\n"); // Utiliser getpeername pour obtenir l'adresse IP du client if (getpeername(sock_nouveau_client, (struct sockaddr *)&client_addr, &client_len) == -1) { log_printf("Erreur ~ Échec de la récupération de l'adresse IP du client\n"); perror("getpeername"); close(sock_nouveau_client); exit(EXIT_FAILURE); } // Convertir l'adresse IP du client en chaîne de caractères char adresse_ip_client[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &client_addr.sin_addr, adresse_ip_client, INET_ADDRSTRLEN) == NULL) { log_printf("Erreur ~ Échec de la conversion de l'adresse IP du client\n"); perror("inet_ntop"); close(sock_nouveau_client); exit(EXIT_FAILURE); } log_printf("Succès ~ %s Connexion Client acceptée\n",