Bonjour à tous,
J'ai comme projet de faire un serveur de messagerie de groupe.
Pour les messages "normaux" entre clients et serveur, je dois utiliser le protocole TCP, et pour les messages de commande type requêtes/réponses ( par exemple le client qui envoie une commande /who pour savoir qui est connecté sur le serveur), je dois utiliser le protocole UDP.
Voilà le code client :
Dans FD_ISSET(0,&read_fds) (ligne 69), il faudra donc que je récupères ce que le client tape (avec un fgets ?), et envoyer le message en UDP ou TCP en fonction de ce qu'il rentre. (si chaîne rentrée = /who alors je l'envoie en UDP, sinon envoie en TCP). Pour ça, pas trop de problèmes je pense, vous m'arrêtez si je me trompe.
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 #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h> int main(int argc, char **argv) { int sockfd; // descripteur de socket struct sockaddr_in serveur; // structure d'adresse qui contiendra les param reseaux du serveur fd_set readfds; // ensemble des descripteurs en lecture qui seront surveilles par select char buf[1024]; // espace necessaire pour stocker le message recu char buf2[1024]; // espace necessaire pour envoyer un message au serveur memset(buf,'\0',1024); // initialisation du buffer qui sera utilisé memset(buf2,'\0',1024); // initialisation de l'autre buffer qui sera utilisé // verification du nombre d'arguments sur la ligne de commande if(argc != 3) { printf("Usage: %s @serveur port_serveur\n", argv[0]); exit(-1); } // creation de la socket sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // initialisation de la structure d'adresse du serveur : // famille d'adresse serveur.sin_family = AF_INET; // recuperation de l'adresse IPv4 du serveur inet_aton(argv[1], &(serveur.sin_addr)); // recuperation du port du serveur serveur.sin_port = htons(atoi(argv[2])); printf("Tentative de connexion\n"); // tentative de connexion if(connect(sockfd,(struct sockaddr*)&serveur,sizeof(serveur)) == -1) { perror("Erreur de connexion -> "); exit(2); } printf("Connexion etablie\n"); while(1) { memset(buf,'\0',1024); // on reinitialise les buffers qui seront utilises memset(buf2,'\0',1024); FD_ZERO(&readfds); // il faut remettre tt les elements ds readfds a chaque recommencement de la boucle, vu que select modifie les ensembles FD_SET(0,&readfds); // on rajoute l'entree standard FD_SET(sockfd,&readfds); // on rajoute la socket de communication avec le serveur if(select(sockfd+1,&readfds,NULL,NULL,NULL) == -1) { perror("Erreur lors de l'appel a select -> "); exit(1); } if(FD_ISSET(0,&readfds)) { // si l'entree standard est dans readfds, alors l'utilisateur en en train de rédiger un message a envoyer if(read(0,buf2,1024) == -1) { // on lit donc ce qui arrive sur l'entrée standard perror("Erreur lors de l'appel a read -> "); exit(1); } if(send(sockfd,buf2,1024,0) == -1) { // puis on l'envoie au serveur perror("Erreur lors de l'appel a send -> "); exit(1); } } if(FD_ISSET(sockfd,&readfds)) { // si la socket de communication est dans readfds, alors le serveur nous a envoye un message if(recv(sockfd,&buf,1024,0) == -1) { perror("Erreur lors de la reception -> "); exit(4); } printf("La chaine recue est: %s\n",buf); // on l'affiche } } }
Le problème est dans le serveur. Voici le code :
Dans la boucle for(i...) et FD_ISSET(...) (à partir de la ligne 106) qui parcourt tous les autres descripteurs du tableau, je ne sais pas où ni comment placer mon recv et mon recvfrom. Comment le serveur peut savoir si il va avoir un message en UDP ou TCP ? Où dois-je placer les commandes nécessaires ?
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 #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h> int main(int argc, char **argv) { int sockfd, sockfd2; // descripteurs de socket fd_set readfds; // ensemble des descripteurs en lecture qui seront surveilles par select int t[FD_SETSIZE]; // tableau qui contiendra tous les descripteurs de sockets, avec une taille egale a la taille max de l'ensemble d'une structure fd_set int taille=0; // nombre de descripteurs dans le tableau precedent char buf[1024]; // espace necessaire pour stocker le message recu memset(buf,'\0',1024); // initialisation du buffer qui sera utilisé struct sockaddr_in my_addr; // structure d'adresse qui contiendra les param reseaux du recepteur struct sockaddr_in client; // structure d'adresse qui contiendra les param reseaux de l'expediteur // taille d'une structure sockaddr_in utile pour la fonction recvfrom socklen_t sin_size = sizeof(struct sockaddr_in); // verification du nombre d'arguments sur la ligne de commande if(argc != 2) { printf("Usage: %s port_local\n", argv[0]); exit(-1); } // creation de la socket sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // initialisation de la structure d'adresse du serveur (pg local) // famille d'adresse my_addr.sin_family = AF_INET; // recuperation du port du serveur my_addr.sin_port = ntohs(atoi(argv[1])); // adresse IPv4 du serveur my_addr.sin_addr.s_addr=htonl(INADDR_ANY); // association de la socket et des param reseaux du serveur if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(my_addr)) != 0) { perror("Erreur lors de l'appel a bind -> "); exit(1); } // indication de la limite MAX de la file d'attente des connexions entrantes if(listen(sockfd,10) != 0) { perror("Erreur lors de l'appel a listen -> "); exit(2); } printf("Attente de connexion\n"); t[0]=sockfd; // on ajoute deja la socket d'ecoute au tableau de descripteurs taille++; // et donc on augmente "taille" while(1) { FD_ZERO(&readfds); //il faut remettre tt les elements ds readfds a chaque recommencement de la boucle, vu que select modifie les ensembles FD_SET(sockfd, &readfds); // ajoute le descripteur sockfd a l'ensemble readfs int j; int sockmax=0; for(j=0;j<taille;j++) { if(t[j] != 0) { FD_SET(t[j],&readfds); // on remet donc tous les elements dans readfds } if(sockmax < t[j]) // et on prend ici le "numero" de socket maximal pour la fonction select { sockmax = t[j]; } } if(select(sockmax+1,&readfds,NULL,NULL,NULL) == -1) { // on utilise le select sur toutes les sockets y compris celle d'ecoute perror("Erreur lors de l'appel a select -> "); exit(1); } if(FD_ISSET(sockfd,&readfds)) { // si la socket d'ecoute est dans readfds, alors qqch lui a ete envoye (=connection d'un client) if((sockfd2 = accept(sockfd,(struct sockaddr*)&client,&sin_size)) == -1) { // on accepte la connexion entrante et on cree une socket... perror("Erreur lors de accept -> "); exit(3); } printf("Connexion etablie avec %s\n", inet_ntoa(client.sin_addr)); taille++; // ...qui est donc ajoutee au tableau de descripteurs t[taille-1]=sockfd2; } int i; for(i=1;i<taille;i++) { // on parcourt tous les autres descripteurs du tableau if(FD_ISSET(t[i],&readfds)) { // si une socket du tableau est dans readfds, alors qqch a ete envoye au serveur par un client if(recv(t[i],&buf,1024,0) == -1) { // on stocke alors le message perror("Erreur lors de la reception -> "); exit(4); } printf("La chaine recue est: %s\n",buf); int k; for(k=1;k<taille;k++) { // puis on l'envoie a tous les clients... if(k != i) { // ...sauf l'envoyeur if(send(t[k],buf,1024,0) == -1) { perror("Erreur lors de l'appel a send -> "); exit(1); } } } memset(buf,'\0',1024); // reinitialisation du buffer } } } }
J'espère avoir été clair, si c'est pas le cas n'hésitez pas à le dire et j'essaierais d'être plus précis !
Merci d'avance !![]()
Partager