Bonjour à tous,

je tente actuellement d'améliorer le fonctionnement d'un serveur multi clients que j'ai réalisé il y a peu en gérant mes clients par liste chainée.

Ca me permet de ne pas avoir un nombre de clients limités et puis ca me fait bosser un peu ^^

J'utilise la fonction select pour gérer la communication/connection/deconnection de mes clients avec le serveur.
Seulement sur ce point je bloque quelque peu.

Voici mon code :

//Serveur.c
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include "appli.h"
 
t_serveur serveur;
WSADATA wsaData;
 
char Buff[BUFF_SIZE];
int max, clean;
 
int Serveur(int sc, int pa)
{
    switch(sc)
    {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Constructeur. Service NEW pour Serveur.
//Création du serveur.
        case SERVEUR_NEW :
            //Initialisation de la DLL permettant d'utiliser les sockets.
            if(WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
            {
                Fin("Initialisation DLL Wsa : Echec.\n");
            }
            //Création de la Socket serveur : Protocole IPv4, Flux de données binaires, Protocole TCP ( mode "connecté")
            if((serveur.Sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
            {
                Fin("Echec lors de la création de la Socket serveur.\n");
            }
 
            //Remplissage de la structure concernant les informations de la Socket
            serveur.Sin.sin_family       = PF_INET;              //Protocole IPv4
            serveur.Sin.sin_addr.s_addr  = htonl(INADDR_ANY);    //Ecoute toutes les adresses IP
            serveur.Sin.sin_port         = htons(PORTSQL);       //Port du serveur
 
            //Liaison de la Socket serveur avec la structure Sockaddr
            //La structure contenant les informations est Sockaddr_in, nous faisons donc un cast
            if(bind(serveur.Sock, (SOCKADDR *)&serveur.Sin, sizeof(serveur.Sin)) == SOCKET_ERROR)
            {
                Fin("Echec du bind.\n");
            }
 
            //Attente de connexions sur la socket serveur
            if(listen(serveur.Sock, 0) == SOCKET_ERROR)
            {
                Fin("Echec de l'écoute sur la Socket.\n");
            }
 
            //Création des clients.
            t_client *clients = NULL;
 
            //Ensemble de descripteurs de fichier.
            fd_set readfds;             //Ici, cet ensemble sera examiné si des données sont disponibles en lecture à partir de l'un
                                        //de ses descripteurs de fichiers.
            max = serveur.Sock;
            serveur.Cpass = "Admin";    //Password pour l'authentification des clients.
 
            break;
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Service RUN pour Serveur.
        case SERVEUR_RUN :
            for(;;)
            {
                FD_ZERO(&readfds);
                FD_SET(serveur.Sock, &readfds);
 
                t_client *now = clients;
 
                while(now != NULL) // on ajoute les descripteurs des fichiers ouverts à l'ensemble fd_set
                {
                    FD_SET(now->Sock, &readfds) ;
                    //printf("%d\n", courant->s);
                    now = now->suivant ;
                }
 
                if(select(max+1, &readfds, NULL, NULL, NULL) == -1)
                {
                    Fin("Erreur lors du select().");
                }
 
                if(FD_ISSET(serveur.Sock, &readfds))
                {
                    //Nouveau Client
                    serveur.Sinsize = sizeof(serveur.Csin);
                    serveur.Csock = accept(serveur.Sock, (SOCKADDR *)(&(serveur.Csin)), &(serveur.Sinsize));
                    if(serveur.Csock == INVALID_SOCKET)
                    {
                        Logs("Echec de la connection du client.\n");
                    }
 
                    now->Sock = serveur.Csock;
 
                    if(now->Sock > max)
                    {
                        max = now->Sock;
                    }
 
                    //Authentification du client
                    purge(Buff);
                    recv(now->Sock, Buff, sizeof(Buff) - 1, 0);
 
                    //La fonction strcmp compare deux chaines Buff et serveur.Cpass et renvoie un entier négatif, nul,
                    //ou positif, si Buff est respectivement inférieure, égale ou supérieure à serveur.Cpass.
                    if((strcmp(Buff, serveur.Cpass) != 0))
                    {
                        purge(Buff);
                        strcpy(Buff, "Bad password !");
                        send(now->Sock, Buff, (int)strlen(Buff), 0);
                        closesocket(now->Sock);
                        purge(Buff);
                        printf("Mauvais password pour (N.%d) %s.\n", now->Sock, inet_ntoa(serveur.Csin.sin_addr));
                    }
 
                    else
                    {
                        printf("Nouvelle connexion (n.%d) : %s se connecte.\n", now->Sock, inet_ntoa(serveur.Csin.sin_addr));
                        strcpy(Buff, "-- Bienvenue sur le serveur SQL");
                        send(now->Sock, Buff, (int)strlen(Buff), 0);
                        purge(Buff);
                        Client(CLIENT_NEW, &clients, 0);
                    }
                }
 
                now = clients;
 
                while(now != NULL)
                {
                    if(FD_ISSET(now->Sock, &readfds))
                    {
                        if(recv(now->Sock, Buff, sizeof(Buff) - 1, 0) == SOCKET_ERROR)
                        {
                            printf("Deconnection (N.%d) de %s.\n", now->Sock, inet_ntoa(serveur.Csin.sin_addr));
                            closesocket(now->Sock);
                            Client(CLIENT_SUPPR, now, 0);
                        }
                        //Reception
                        else
                        {
                            printf("%s dit : %s\n", inet_ntoa(serveur.Csin.sin_addr), Buff);
                            purge(Buff);
                        }
 
                        //Envoi
                        strcpy(Buff, "Message.\n");
                        send(now->Sock, Buff, (int)strlen(Buff), 0);
                        purge(Buff);
                    }
                    now = now->suivant;
                }
            }
            break;
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Destructeur. Service DEL pour Serveur.
        case SERVEUR_DEL :
            closesocket(serveur.Sock);   //Fermeture de la Socket serveur.
            WSACleanup();                //Libération de la dll.
            break;
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        default :
            Fin("SERVEUR_*** : bad sc");
            break;
    }
    return 0;
}
 
void purge(char *Buff)
{
    for(clean = 0; clean < BUFF_SIZE; clean++)
    {
        Buff[clean] = '\0';
    }
}
//Serveur.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define SERVEUR_NEW 203
#define SERVEUR_RUN 204
#define SERVEUR_DEL 205
#define SERVEUR_ACCESS 206
 
#define BUFF_SIZE 1024
#define PORTSQL 10000
 
typedef struct tt_serveur {
    SOCKET Sock;
    SOCKADDR_IN Sin;
    SOCKET Csock;
    SOCKADDR_IN Csin;
    size_t Sinsize;
    char *Cpass;
}t_serveur;
 
int Serveur(int sc, int pa);
void purge(char *Buff);
//Client.c (contenu dans le projet serveur ...)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include "appli.h"
 
int Client(int sc, t_client **p, int pa)
{
    switch(sc)
    {
 
/******************************************************************************************************************************/
//Constructeur. Service NEW pour Client.
//Création d'un nouveau client.
        case CLIENT_NEW:
            puts("");
            t_client *client = malloc(sizeof(t_client)); //Création d'un nouveau client.
            if(!client)
            {
                Fin("CLIENT_NEW : malloc a échoué");
            }
            client->Valeur = pa;   //Affectation de la valeur au client.
            client->suivant = *p;     //Adresse du client suivant.
            *p = client;          //Le pointeur pointe sur le dernier client.
            break;
 
/******************************************************************************************************************************/
//Service ENUM pour Client.
//Liste le nombre de clients
        case CLIENT_ENUM:
            pa = 0;
            while(p)
            {
                pa++;
                p = p->suivant;
            }
            printf("Il y a actuellement %d clients de connectés.\n", pa);
            break;
 
/******************************************************************************************************************************/
//Service SUPPR pour Client.
//Enlève un client de la liste.
        case CLIENT_SUPPR:
            puts("");
            int Val;
            t_client *temp;
 
            if(!*p)
            {
                return -1;      //Il n'y a plus de clients.
            }
 
            temp = (*p)->suivant;
            Val = (*p)->Valeur;
            free(*p);           //Libération de la mémoire allouée au pointeur.
            *p = temp;          //Le pointeur pointe sur le dernier client.
            closesocket(pa->Sock);
            return Val;
            break;
 
/******************************************************************************************************************************/
//Service DEL pour Client.
//Destructeur. Supprime tous les clients.
        case CLIENT_DEL:
            t_client *temp;
 
            while(*p)
            {
                temp = (*p)->suivant;
                free(*p);
                *p = temp;
                closesocket(temp.Sock);
            }
            break;
 
/******************************************************************************************************************************/
        default:
            Fin("CLIENT_*** : bad sc");
            break;
 
/******************************************************************************************************************************/
    }
    return 0;
}
//Client.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
#define CLIENT_NEW 200
#define CLIENT_ENUM 201
#define CLIENT_SUPPR 202
#define CLIENT_DEL 203
 
typedef struct tt_client{
    int Valeur;
    struct t_client *suivant;
    SOCKET Sock;            //Socket Client
}t_client;
 
int Client(int sc, t_client **p, int pa);
Je crois qu'il y a quelques incohérence avec la liste chainée, mais je débute sur ce chapitre !