Commit 0ae6908740c8484212f66820440c1c7428745d24
1 parent
0042f330
Ajout des fichiers
Showing
30 changed files
with
1243 additions
and
0 deletions
Show diff stats
... | ... | @@ -0,0 +1,16 @@ |
1 | +Les balises de débug servent a imprimer des infos suplémentaires en cas de besoin, sans qu'elles apparaissent dans le programme final. | |
2 | + | |
3 | +--- Dans le code : | |
4 | +#ifdef DEBUG | |
5 | + printf("Je ne print que quand DEBUG est définit\n"); | |
6 | +#endif | |
7 | + | |
8 | +--- Dans le make (activation du mode DEBUG) | |
9 | +debug: CFLAGS += -g -DDEBUG | |
10 | +debug: all | |
11 | + | |
12 | +explication : | |
13 | + CFLAGS sont les drapeaux passé à gcc (contien des choses comme -lpthread ou autre) | |
14 | + On y rajoute -g, pour que gcc nous affiche plus d'information sur la compilation | |
15 | + On y rajoute -DDEBUG, -D permet d'ajouter une balise (comme si on avait fait une #define DEBUG) | |
16 | + DEBUG est défini donc, les messages se print. | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +TARGET=libnet | |
2 | +DIR_TARGET=../libs | |
3 | +CFLAGS=-Wall -pedantic -Wextra -I $(DIR_TARGET) | |
4 | +CLIB=ar cq | |
5 | +CC=gcc | |
6 | + | |
7 | +all: $(TARGET).a | |
8 | + | |
9 | +debug: CFLAGS += -g -DDEBUG | |
10 | +debug: all | |
11 | + | |
12 | +clean: | |
13 | + rm -f *.o *.a | |
14 | + rm -f $(DIR_TARGET)/$(TARGET).a | |
15 | + rm -f $(DIR_TARGET)/$(TARGET).h | |
16 | + | |
17 | +$(TARGET).o: $(TARGET).c $(TARGET).h | |
18 | + $(CC) -c $(CFLAGS) -o $@ $< | |
19 | + | |
20 | +$(TARGET).a: $(TARGET).o | |
21 | + rm -rf $@ | |
22 | + $(CLIB) $@ $+ | |
23 | + mkdir $(DIR_TARGET) -p | |
24 | + cp $(TARGET).a $(DIR_TARGET)/$(TARGET).a | |
25 | + cp $(TARGET).h $(DIR_TARGET)/$(TARGET).h | |
26 | + | ... | ... |
... | ... | @@ -0,0 +1,277 @@ |
1 | +#include <sys/types.h> | |
2 | +#include <sys/socket.h> | |
3 | +#include <netdb.h> | |
4 | +#include <errno.h> | |
5 | +#include <stdlib.h> | |
6 | +#include <netinet/udp.h> | |
7 | +#include <netinet/in.h> | |
8 | +#include <netinet/ip.h> | |
9 | +#include <string.h> | |
10 | +#include <stdio.h> | |
11 | +#include <arpa/inet.h> | |
12 | +#include <unistd.h> | |
13 | +#include <stdint.h> | |
14 | + | |
15 | +#define MAX_TCP_CONNEXION 10 | |
16 | +#define BUFFER_SIZE 1024 | |
17 | + | |
18 | +//Fonction permettant d'envoyer en broadcast un message | |
19 | +void sendUDPBroadcast(unsigned char *message, int taille_message, int port) { | |
20 | + int broadcast_enable = 1; | |
21 | + //Option broadcast ON | |
22 | + int s = socket(AF_INET, SOCK_DGRAM, 0); | |
23 | + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) | |
24 | + if(s < 0){ | |
25 | + //Test de la valeur de retour de la socket | |
26 | + perror("sendUDPBroadcast.socket"); | |
27 | + exit(-1); | |
28 | + } | |
29 | + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable)) < 0) { | |
30 | + //Mise option broadcast à la socket | |
31 | + perror("sendUDPBroadcast.setsockopt"); | |
32 | + exit(-1); | |
33 | + } | |
34 | + | |
35 | + struct sockaddr_in broadcast_address; | |
36 | + memset(&broadcast_address, 0, sizeof(broadcast_address)); | |
37 | + broadcast_address.sin_family = AF_INET; | |
38 | + broadcast_address.sin_port = htons(port); | |
39 | + broadcast_address.sin_addr.s_addr = INADDR_BROADCAST; //255.255.255.255 | |
40 | + | |
41 | + //Envoie du message grâce à la socket | |
42 | + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &broadcast_address, | |
43 | + sizeof(broadcast_address)) < 0 ) { | |
44 | + perror("sendUDPBroadcast.sendto"); | |
45 | + exit(-1); | |
46 | + } | |
47 | +} | |
48 | + | |
49 | + | |
50 | +void sendUDPUnicast(char *address, unsigned char *message, int taille_message, int port) { | |
51 | + int s = socket(AF_INET, SOCK_DGRAM, 0); | |
52 | + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) | |
53 | + if(s < 0){ | |
54 | + //Test de la valeur de retour de la socket | |
55 | + perror("sendUDPUnicast.socket"); | |
56 | + exit(-1); | |
57 | + } | |
58 | + struct sockaddr_in unicast_address; | |
59 | + //Creation structure adresse de destination | |
60 | + memset(&unicast_address, 0, sizeof(unicast_address)); | |
61 | + //Mise à zéro de la structure d'adresse | |
62 | + unicast_address.sin_family = AF_INET; | |
63 | + unicast_address.sin_port = htons(port); | |
64 | + //Mise du port en ordre du réseau (big endian) | |
65 | + unicast_address.sin_addr.s_addr = inet_addr(address); | |
66 | + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &unicast_address, sizeof(unicast_address)) < 0 ) { | |
67 | + perror("sendUDPUnicast.sendto"); | |
68 | + exit(-1); | |
69 | + } | |
70 | +} | |
71 | + | |
72 | +// Retourne l'adresse ip d'une connexion active | |
73 | +static int socketVersNomUDP(struct sockaddr *padresse, char *nom){ | |
74 | + void *ip; | |
75 | + int taille_nom; | |
76 | + if(padresse->sa_family == AF_INET){ | |
77 | + struct sockaddr_in *ipv4 = (struct sockaddr_in *) padresse; | |
78 | + ip = (void *) &ipv4->sin_addr; | |
79 | + taille_nom = INET_ADDRSTRLEN; | |
80 | + } | |
81 | + if(padresse->sa_family == AF_INET6){ | |
82 | + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) padresse; | |
83 | + ip = (void *)&ipv6->sin6_addr; | |
84 | + taille_nom = INET6_ADDRSTRLEN; | |
85 | + } | |
86 | + char nom_deco[20]; | |
87 | + inet_ntop(padresse->sa_family, ip, nom_deco, taille_nom); | |
88 | + sprintf(nom, "%s", nom_deco + 7); | |
89 | + return 0; | |
90 | +} | |
91 | +static int socketVersNomTCP(int s, char *nom){ | |
92 | + struct sockaddr_storage adresse; | |
93 | + struct sockaddr *padresse = (struct sockaddr *) &adresse; | |
94 | + socklen_t taille = sizeof adresse; | |
95 | + int statut; | |
96 | + | |
97 | + /* Recupere l'adresse de la socket distante */ | |
98 | + statut = getpeername(s, padresse, &taille); | |
99 | + if(statut<0){ | |
100 | + perror("socketVersNom.getpeername"); | |
101 | + return -1; | |
102 | + } | |
103 | + | |
104 | + /* Recupere le nom de la machine */ | |
105 | + return socketVersNomUDP(padresse, nom); | |
106 | +} | |
107 | + | |
108 | +// Fonction permettant de créer le serveur TCP | |
109 | +int initialisationServeurTCP(char *service){ | |
110 | + struct addrinfo precisions, *resultat, *origine; | |
111 | + int statut; | |
112 | + int s; | |
113 | + | |
114 | + /* Construction de la structure adresse */ | |
115 | + memset(&precisions, 0, sizeof precisions); | |
116 | + precisions.ai_family = AF_UNSPEC; | |
117 | + precisions.ai_socktype = SOCK_STREAM; | |
118 | + precisions.ai_flags = AI_PASSIVE; | |
119 | + statut = getaddrinfo(NULL, service, &precisions, &origine); | |
120 | + if(statut < 0){ | |
121 | + perror("initialisationSocketUDP.getaddrinfo"); | |
122 | + exit(EXIT_FAILURE); | |
123 | + } | |
124 | + struct addrinfo *p; | |
125 | + for(p = origine, resultat = origine; p != NULL; p = p->ai_next) { | |
126 | + if(p->ai_family == AF_INET6){ | |
127 | + resultat = p; | |
128 | + break; | |
129 | + } | |
130 | + } | |
131 | + | |
132 | + /* Creation d'une socket */ | |
133 | + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); | |
134 | + if(s < 0){ | |
135 | + perror("initialisationSocketUDP.socket"); | |
136 | + exit(EXIT_FAILURE); | |
137 | + } | |
138 | + | |
139 | + /* Options utiles */ | |
140 | + int vrai = 1; | |
141 | + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai))<0) { | |
142 | + perror("initialisationServeurUDPgenerique.setsockopt (REUSEADDR)"); | |
143 | + exit(-1); | |
144 | + } | |
145 | + | |
146 | + /* Specification de l'adresse de la socket */ | |
147 | + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); | |
148 | + if(statut<0) { | |
149 | + perror("initialisationServeurUDP.bind"); | |
150 | + exit(-1); | |
151 | + } | |
152 | + | |
153 | + /* Liberation de la structure d'informations */ | |
154 | + freeaddrinfo(origine); | |
155 | + | |
156 | + /* Taille de la queue d'attente */ | |
157 | + statut = listen(s, MAX_TCP_CONNEXION); | |
158 | + if(statut < 0) | |
159 | + return -1; | |
160 | + return s; | |
161 | +} | |
162 | + | |
163 | +// Accepte toutes les connexions au serveur TCP et execute la fonction en argument | |
164 | +int boucleServeurTCP(int socket, void (*traitement)(int, char *)){ | |
165 | + while(1){ | |
166 | + // accept connection | |
167 | + struct sockaddr ip_src; | |
168 | + socklen_t ip_len = sizeof(struct sockaddr); | |
169 | + int socket_dialogue = accept(socket, &ip_src, &ip_len); | |
170 | + if(socket_dialogue < 0){ | |
171 | + perror("boucleServeur.accept"); | |
172 | + return -1; | |
173 | + } | |
174 | + | |
175 | + // get ip addr | |
176 | + char char_ip[20]; | |
177 | + int status = socketVersNomTCP(socket_dialogue, char_ip); | |
178 | + if(status < 0) | |
179 | + perror("socketVersNom"); | |
180 | + | |
181 | + // callback function | |
182 | + traitement(socket_dialogue, char_ip); | |
183 | + } | |
184 | + return 0; | |
185 | +} | |
186 | + | |
187 | +// Creation d'un serveur UDP | |
188 | +int initialisationServeurUDP(char *service){ | |
189 | + struct addrinfo precisions, *resultat, *origine; | |
190 | + int statut; | |
191 | + int s; | |
192 | + | |
193 | + /* Construction de la structure adresse */ | |
194 | + memset(&precisions, 0, sizeof precisions); | |
195 | + precisions.ai_family = AF_UNSPEC; | |
196 | + precisions.ai_socktype = SOCK_DGRAM; | |
197 | + precisions.ai_flags = AI_PASSIVE; | |
198 | + statut = getaddrinfo(NULL, service, &precisions, &origine); | |
199 | + if(statut < 0){ perror("initialisationSocketUDP.getaddrinfo"); exit(EXIT_FAILURE); } | |
200 | + | |
201 | + struct addrinfo *p; | |
202 | + for(p=origine, resultat=origine; p!=NULL; p=p->ai_next) | |
203 | + if(p->ai_family == AF_INET6){ resultat=p; break; } | |
204 | + | |
205 | + /* Creation d'une socket */ | |
206 | + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); | |
207 | + if(s<0){ perror("initialisationSocketUDP.socket"); exit(EXIT_FAILURE); } | |
208 | + | |
209 | + /* Options utiles */ | |
210 | + int vrai = 1; | |
211 | + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai)) < 0){ | |
212 | + perror("initialisationServeurUDPgenerique.setsockopt (REUSEADDR)"); | |
213 | + exit(-1); | |
214 | + } | |
215 | + | |
216 | + /* Specification de l'adresse de la socket */ | |
217 | + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); | |
218 | + if(statut < 0) { perror("initialisationServeurUDP.bind"); exit(-1); } | |
219 | + | |
220 | + /* Liberation de la structure d'informations */ | |
221 | + freeaddrinfo(origine); | |
222 | + | |
223 | + return s; | |
224 | +} | |
225 | + | |
226 | +// Reception des messages UDP et execute la fonction passee en argument | |
227 | +int boucleServeurUDP(int s, void (*traitement)(unsigned char *, int, char *)){ | |
228 | + while(1){ | |
229 | + struct sockaddr_storage adresse; | |
230 | + struct sockaddr *padresse = (struct sockaddr *) &adresse; | |
231 | + socklen_t taille = sizeof(adresse); | |
232 | + unsigned char message[BUFFER_SIZE]; | |
233 | + | |
234 | + int nboctets = recvfrom(s, message, BUFFER_SIZE, 0, (struct sockaddr *) padresse, &taille); | |
235 | + if(nboctets < 0) return -1; | |
236 | + | |
237 | + /* Recupere le nom de la machine */ | |
238 | + char char_ip[20]; | |
239 | + int status = socketVersNomUDP(padresse, char_ip); | |
240 | + if(status < 0) | |
241 | + perror("socketVersNom"); | |
242 | + | |
243 | + traitement(message, nboctets, char_ip); | |
244 | + } | |
245 | + return 0; | |
246 | +} | |
247 | + | |
248 | +// Initialise un client TCP | |
249 | +int openTCPClient(char *hote, int port) { | |
250 | + int s; | |
251 | + struct sockaddr_in adresse; | |
252 | + socklen_t taille = sizeof adresse; | |
253 | + | |
254 | + // creation socket | |
255 | + s = socket(PF_INET, SOCK_STREAM, 0); | |
256 | + if(s<0){ perror("connexionServeur.socket"); exit(-1); } | |
257 | + | |
258 | + // connexion | |
259 | + memset(&adresse, 0, sizeof(adresse)); | |
260 | + adresse.sin_family=AF_INET; | |
261 | + adresse.sin_port = htons(port); | |
262 | + adresse.sin_addr.s_addr = inet_addr(hote); | |
263 | + if(connect(s,(struct sockaddr *)&adresse, taille)<0) return -1; | |
264 | + return s; | |
265 | +} | |
266 | + | |
267 | +// Envoie un message TCP sur une connexion active | |
268 | +void sendTCP(int socket, char *message, int length_message){ | |
269 | + if(length_message <= 0) | |
270 | + return; | |
271 | + write(socket, message, length_message); | |
272 | +} | |
273 | + | |
274 | +// Recois un message TCP sur une connexion active | |
275 | +int receiveTCP(int socket, char *message, int max_length){ | |
276 | + return read(socket, message, max_length); | |
277 | +} | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +#ifndef LIBNET_H | |
2 | +#define LIBNET_H | |
3 | + | |
4 | +#include <stdint.h> | |
5 | + | |
6 | +int sendUDPBroadcast(unsigned char *message, int taille_message, int port); | |
7 | +int sendUDPUnicast(char *address, unsigned char *message, int taille_message, int port); | |
8 | + | |
9 | +int initialisationServeurTCP(char *service); | |
10 | +int boucleServeurTCP(int socket, void (*traitement)(int, char *)); | |
11 | + | |
12 | +int initialisationServeurUDP(char *service); | |
13 | +int boucleServeurUDP(int s, void (*traitement)(unsigned char *, int, char *)); | |
14 | + | |
15 | +int openTCPClient(char *hote, int port); | |
16 | +void sendTCP(int socket, char *message, int length_message); | |
17 | +int receiveTCP(int socket, char *message, int max_length); | |
18 | + | |
19 | +#endif | ... | ... |
No preview for this file type
... | ... | @@ -0,0 +1,25 @@ |
1 | +TARGET=toto | |
2 | +DIR_TARGET=./toto_lib | |
3 | +CFLAGS=-Wall -pedantic -Wextra -I $(DIR_TARGET) | |
4 | +CLIB=ar cq | |
5 | +CC=gcc | |
6 | + | |
7 | +all: $(TARGET).a | |
8 | + | |
9 | +debug: CFLAGS += -g -DDEBUG | |
10 | +debug: all | |
11 | + | |
12 | +clean: | |
13 | + rm -f *.o *.a | |
14 | + rm -f $(DIR_TARGET)/$(TARGET).a | |
15 | + rm -f $(DIR_TARGET)/$(TARGET).h | |
16 | + | |
17 | +$(TARGET).o: $(TARGET).c $(TARGET).h | |
18 | + $(CC) -c $(CFLAGS) -o $@ $< | |
19 | + | |
20 | +$(TARGET).a: $(TARGET).o | |
21 | + rm -rf $@ | |
22 | + $(CLIB) $@ $+ | |
23 | + mkdir $(DIR_TARGET) -p | |
24 | + cp $(TARGET).a $(DIR_TARGET)/$(TARGET).a | |
25 | + cp $(TARGET).h $(DIR_TARGET)/$(TARGET).h | ... | ... |
... | ... | @@ -0,0 +1,30 @@ |
1 | +Une librairie (un .a) est construit à partir de .o | |
2 | + Rappel générer un .o : gcc <fichier(s)> -c | |
3 | + | |
4 | +Nom d'une librairie : TOUJOURS lib_____.a | |
5 | + | |
6 | +Création : | |
7 | + ar cq <nom_archive> <nom_.o> | |
8 | +"q" permet la création de la librairie (pour les options taper ar dans le terminal) | |
9 | + | |
10 | +Attention : il faut aussi donner le .h avec le .a | |
11 | + | |
12 | +Utilisation d'une librairie : | |
13 | + - #include <_____.h> | |
14 | + - gcc [...] -L <archives_dir> -I <archives_dir> | |
15 | + | |
16 | +Utilisation du squelette Makefile : | |
17 | + - remplacer "toto" par la cible (ex: libnet) | |
18 | + - remplacer "./toto_lib" par le dossier qui contiendra la librairie (ex: ../libs) | |
19 | + | |
20 | +Ce que fait le make (make all) : | |
21 | + - compile le TARGET.c en .o | |
22 | + - crée la librairie .a | |
23 | + - copie .a et .h dans le dossier DIR_TRAGET | |
24 | + | |
25 | +Ce que fait le make clean : | |
26 | + - efface le .o et le .a dans ./ | |
27 | + - efface le .a et le .h du dossier DIR_TRAGET | |
28 | + | |
29 | +Ce que fait le make debug : | |
30 | + (voir la partie sur les flags de debug dans ../Debug) | |
0 | 31 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,41 @@ |
1 | +# | |
2 | +# Variables d'environnement | |
3 | +# | |
4 | +export CC = gcc | |
5 | +export LD = gcc | |
6 | +export CLIB = ar cq | |
7 | +export CFLAGS = -Wall -Wextra -pedantic | |
8 | + | |
9 | +# | |
10 | +# Constantes liees au projet | |
11 | +# | |
12 | + | |
13 | +DIRS = Threads Network Sioux Tangible | |
14 | + | |
15 | +# | |
16 | +# La cible generale | |
17 | +# | |
18 | + | |
19 | +all: $(patsubst %, _dir_%, $(DIRS)) | |
20 | + | |
21 | +$(patsubst %,_dir_%,$(DIRS)): | |
22 | + cd $(patsubst _dir_%,%,$@) && make | |
23 | + | |
24 | +# | |
25 | +# La cible de debug | |
26 | +# | |
27 | + | |
28 | +debug: CFLAGS += -g -DDEBUG | |
29 | +debug: $(patsubst %, _debug_%, $(DIRS)) | |
30 | + | |
31 | +$(patsubst %,_debug_%,$(DIRS)): | |
32 | + cd $(patsubst _debug_%,%,$@) && make debug | |
33 | + | |
34 | +# | |
35 | +# La cible de nettoyage | |
36 | +# | |
37 | + | |
38 | +clean: $(patsubst %, _clean_%, $(DIRS)) | |
39 | + | |
40 | +$(patsubst %,_clean_%,$(DIRS)): | |
41 | + cd $(patsubst _clean_%,%,$@) && make clean | ... | ... |
... | ... | @@ -0,0 +1,18 @@ |
1 | +Appeler un makefile depuis un makefile "maitre". | |
2 | + | |
3 | +Dans les makefiles "esclaves", créer les cibles que va appeler le makefile "maitre" (all, clean, debug, etc...) | |
4 | + | |
5 | +Pour les appeler à partir du makefile maitre : (ex avec clean) | |
6 | + | |
7 | +clean: $(patsubst %, _clean_%, $(DIRS)) | |
8 | +$(patsubst %,_clean_%,$(DIRS)): | |
9 | + cd $(patsubst _clean_%,%,$@) && make clean | |
10 | + | |
11 | +Ce que fait la focntion plus haut : | |
12 | + - parmis la liste des dossiers donné dans la variable DIRS | |
13 | + - fait un cd au dossier | |
14 | + - fait un make clean | |
15 | + | |
16 | +Les variables d'environnement (export CC, etc...) ne sont pas obligatoire mais permettent d'unifier les plus communes. | |
17 | +Exemple : dans le makefile "eclave" $(CC), n'est pas définit mais le makefile "maitre" le définit avec un export CC=gcc. | |
18 | + | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +#include <stdio.h> | |
2 | +#include <stdlib.h> // pour exit(0); | |
3 | +#include <unistd.h> // pour sleep(1); | |
4 | +#include <signal.h> | |
5 | + | |
6 | +/** Fonction appelé lors de la reception du signal */ | |
7 | +void handler(int sig){ | |
8 | + printf("Signal reçu :%d:", sig); | |
9 | + exit(0); | |
10 | +} | |
11 | + | |
12 | +int main(void){ | |
13 | + // à mettre en début de main | |
14 | + struct sigaction action; | |
15 | + action.sa_handler = handler; | |
16 | + sigaction(SIGINT, &action, NULL); // On écoute le signal SIGINT (CTRL+C) | |
17 | + | |
18 | + // attente / à remplacer par la suite | |
19 | + while(1) sleep(1); | |
20 | +} | |
0 | 21 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,78 @@ |
1 | +#include <signal.h> | |
2 | + | |
3 | +--- codes signaux | |
4 | +Signal CTRL+C = SIGINT (ou 2) | |
5 | + | |
6 | +codes complets : | |
7 | +(voir à la fin / pas très utile) | |
8 | + | |
9 | +--- Envoi de signaux : | |
10 | + int kill(pid_t pid, int sig); // pid_t ~= int | |
11 | + | |
12 | +pid : >0 processus précis | |
13 | + =0 processus dans le même groupe que notre processus | |
14 | + <0 tous les processus du groupe "-pid" | |
15 | + | |
16 | + | |
17 | +--- Reception de signaux : | |
18 | +Définition d'un handler (fonction appelé lors de la recpetion d'un signal) : | |
19 | + void handler(int sig){ | |
20 | + //... | |
21 | + } | |
22 | + | |
23 | +Enregistrement du handler dans sigaction : | |
24 | + struct sigaction action; | |
25 | + action.sa_handler; | |
26 | + | |
27 | +La fonction sigaction : | |
28 | + int sigaction(int sig_to_listen, const struct sigaction *sigaction, struct sigaction *sigaction_anc); //sigaction_anc = NULL (très, très) souvent | |
29 | + | |
30 | +Déclaration du sigaction pour détecter les signaux (ex: SIG_INT) : | |
31 | + sigaction(SIGINT, &action, NULL); | |
32 | + | |
33 | +--- Attendre un signal | |
34 | +la fonction : | |
35 | + int pause (void); | |
36 | + | |
37 | + | |
38 | +--- Commandes terminal utiles | |
39 | +voir la liste des processus : | |
40 | + ps / ps -a | |
41 | + | |
42 | +tuer un processus avec un signal particulier : | |
43 | + kill -<signal> <pid> / kill -s <signal> <pid> | |
44 | + Note : le signal 9 (kill -9 <pid>) tue n'importe quel processus imédiatement | |
45 | + | |
46 | +--- Utilisation du squelette | |
47 | +Remplacer les balises "TODO" par les valeurs souhaitées | |
48 | + | |
49 | + | |
50 | + | |
51 | + | |
52 | +--- Tous les codes de signaux | |
53 | + | |
54 | +(venant de l'aide de la commande "man 7 signal") | |
55 | + | |
56 | +Signal Value Action Comment | |
57 | +────────────────────────────────────────────────────────────────────── | |
58 | +SIGHUP 1 Term Hangup detected on controlling terminal | |
59 | + or death of controlling process | |
60 | +SIGINT 2 Term Interrupt from keyboard | |
61 | +SIGQUIT 3 Core Quit from keyboard | |
62 | +SIGILL 4 Core Illegal Instruction | |
63 | +SIGABRT 6 Core Abort signal from abort(3) | |
64 | +SIGFPE 8 Core Floating-point exception | |
65 | +SIGKILL 9 Term Kill signal | |
66 | +SIGSEGV 11 Core Invalid memory reference | |
67 | +SIGPIPE 13 Term Broken pipe: write to pipe with no | |
68 | + readers; see pipe(7) | |
69 | +SIGALRM 14 Term Timer signal from alarm(2) | |
70 | +SIGTERM 15 Term Termination signal | |
71 | +SIGUSR1 30,10,16 Term User-defined signal 1 | |
72 | +SIGUSR2 31,12,17 Term User-defined signal 2 | |
73 | +SIGCHLD 20,17,18 Ign Child stopped or terminated | |
74 | +SIGCONT 19,18,25 Cont Continue if stopped | |
75 | +SIGSTOP 17,19,23 Stop Stop process | |
76 | +SIGTSTP 18,20,24 Stop Stop typed at terminal | |
77 | +SIGTTIN 21,21,26 Stop Terminal input for background process | |
78 | +SIGTTOU 22,22,27 Stop Terminal output for background process | |
0 | 79 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +#include <stdio.h> | |
2 | +#include <signal.h> | |
3 | + | |
4 | +void handler(int sig){ | |
5 | + //TODO code à executer à la recpetion du signal... | |
6 | +} | |
7 | + | |
8 | +int main(void){ | |
9 | + struct sigaction action; | |
10 | + action.sa_handler = handler; | |
11 | + sigaction(/*TODO signal à écouter...*/, &action, NULL); | |
12 | + | |
13 | + // TODO programme normal... | |
14 | +} | |
0 | 15 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,74 @@ |
1 | +#include <stdio.h> | |
2 | +#include <string.h> // pour strlen() | |
3 | +#include <stdlib.h> // pour exit() | |
4 | +#include <sys/socket.h> | |
5 | +#include <netinet/in.h> | |
6 | +#include <netinet/ip.h> | |
7 | +#include <netinet/tcp.h> | |
8 | +#include <arpa/inet.h> | |
9 | +#include <unistd.h> | |
10 | + | |
11 | +#define BUFFER_SIZE 1000 | |
12 | + | |
13 | +// Initialise un client TCP, retourne la socket creee | |
14 | +int openTCPClient(char *hote, int port) { | |
15 | + int s; | |
16 | + struct sockaddr_in adresse; | |
17 | + socklen_t taille = sizeof adresse; | |
18 | + | |
19 | + // creation socket | |
20 | + s = socket(PF_INET, SOCK_STREAM, 0); | |
21 | + if(s<0){ perror("connexionServeur.socket"); exit(-1); } | |
22 | + | |
23 | + // connexion | |
24 | + memset(&adresse, 0, sizeof(adresse)); | |
25 | + adresse.sin_family=AF_INET; | |
26 | + adresse.sin_port = htons(port); | |
27 | + adresse.sin_addr.s_addr = inet_addr(hote); | |
28 | + if(connect(s,(struct sockaddr *)&adresse, taille)<0) return -1; | |
29 | + return s; | |
30 | +} | |
31 | + | |
32 | +// Envoie un message TCP sur une connexion active | |
33 | +void sendTCP(int socket, char *message, int length_message){ | |
34 | + if(length_message <= 0) | |
35 | + return; | |
36 | + write(socket, message, length_message); | |
37 | +} | |
38 | + | |
39 | +// Recois un message TCP sur une connexion active. Retourne le nombre de char recu | |
40 | +int receiveTCP(int socket, char *message, int max_length){ | |
41 | + return read(socket, message, max_length); | |
42 | +} | |
43 | + | |
44 | +// Ferme le connection entre le serveur et le client | |
45 | +void closeTCPCLient(int socket){ | |
46 | + shutdown(socket, SHUT_RDWR); | |
47 | +} | |
48 | + | |
49 | +int main(void){ | |
50 | + char google_addr[50] = "172.217.7.163"; | |
51 | + | |
52 | + // Open connection | |
53 | + int socket = openTCPClient(google_addr, 80); | |
54 | + | |
55 | + // Send GET HTTP request test | |
56 | + char message[1000] = "GET / HTTP/1.1\n\n\0"; | |
57 | + sendTCP(socket, message, strlen(message)); | |
58 | + | |
59 | + // Recieve HTTP response | |
60 | + char rep[BUFFER_SIZE]; | |
61 | + int status = receiveTCP(socket, rep, BUFFER_SIZE); | |
62 | + if(status < 0){ | |
63 | + printf("Erreur de recieve\n"); | |
64 | + exit(-1); | |
65 | + } | |
66 | + | |
67 | + // affichage | |
68 | + printf("%s\n", rep); | |
69 | + | |
70 | + // déconnection | |
71 | + closeTCPCLient(socket); | |
72 | + | |
73 | + return 0; | |
74 | +} | |
0 | 75 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,115 @@ |
1 | +#include <stdio.h> | |
2 | +#include <stdlib.h> // pour exit() | |
3 | +#include <string.h> | |
4 | +#include <sys/socket.h> | |
5 | +#include <sys/types.h> | |
6 | +#include <netinet/in.h> | |
7 | +#include <netinet/ip.h> | |
8 | +#include <netinet/tcp.h> | |
9 | +#include <netdb.h> | |
10 | + | |
11 | +#define BUFFER_SIZE 1000 | |
12 | +#define MAX_TCP_CONNEXION 5 | |
13 | + | |
14 | +// Fonction permettant de créer le serveur TCP | |
15 | +// service est le numéro ou nom de port (ex: "80" ou "http") | |
16 | +int initialisationServeurTCP(char *service){ | |
17 | + struct addrinfo precisions, *resultat, *origine; | |
18 | + int statut; | |
19 | + int s; | |
20 | + | |
21 | + /* Construction de la structure adresse */ | |
22 | + memset(&precisions, 0, sizeof precisions); | |
23 | + precisions.ai_family = AF_UNSPEC; | |
24 | + precisions.ai_socktype = SOCK_STREAM; | |
25 | + precisions.ai_flags = AI_PASSIVE; | |
26 | + statut = getaddrinfo(NULL, service, &precisions, &origine); | |
27 | + if(statut < 0){ | |
28 | + perror("initialisationSocketTCP.getaddrinfo"); | |
29 | + exit(EXIT_FAILURE); | |
30 | + } | |
31 | + struct addrinfo *p; | |
32 | + for(p = origine, resultat = origine; p != NULL; p = p->ai_next) { | |
33 | + if(p->ai_family == AF_INET6){ | |
34 | + resultat = p; | |
35 | + break; | |
36 | + } | |
37 | + } | |
38 | + | |
39 | + /* Creation d'une socket */ | |
40 | + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); | |
41 | + if(s < 0){ | |
42 | + perror("initialisationSocketTCP.socket"); | |
43 | + exit(EXIT_FAILURE); | |
44 | + } | |
45 | + | |
46 | + /* Options utiles */ | |
47 | + int vrai = 1; | |
48 | + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai))<0) { | |
49 | + perror("initialisationServeurTCPgenerique.setsockopt (REUSEADDR)"); | |
50 | + exit(-1); | |
51 | + } | |
52 | + | |
53 | + /* Specification de l'adresse de la socket */ | |
54 | + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); | |
55 | + if(statut<0) { | |
56 | + perror("initialisationServeurTCP.bind"); | |
57 | + exit(-1); | |
58 | + } | |
59 | + | |
60 | + /* Liberation de la structure d'informations */ | |
61 | + freeaddrinfo(origine); | |
62 | + | |
63 | + /* Taille de la queue d'attente */ | |
64 | + statut = listen(s, MAX_TCP_CONNEXION); | |
65 | + if(statut < 0) | |
66 | + return -1; | |
67 | + return s; | |
68 | +} | |
69 | + | |
70 | +// Accepte toutes les connexions au serveur TCP et execute la fonction en argument | |
71 | +// ATTENTION : non multi-threadé ! -> il faut un pthread_create dans traitement pour le multi-thread. | |
72 | +int boucleServeurTCP(int socket, void (*traitement)(int)){ | |
73 | + while(1){ | |
74 | + // accept connection | |
75 | + struct sockaddr ip_src; | |
76 | + socklen_t ip_len = sizeof(struct sockaddr); | |
77 | + int socket_dialogue = accept(socket, &ip_src, &ip_len); | |
78 | + if(socket_dialogue < 0){ | |
79 | + perror("boucleServeur.accept"); | |
80 | + return -1; | |
81 | + } | |
82 | + | |
83 | + // callback function | |
84 | + traitement(socket_dialogue); | |
85 | + } | |
86 | + return 0; | |
87 | +} | |
88 | + | |
89 | +void exemple_traitement(int socket){ | |
90 | + FILE *dialogue = fdopen(socket, "a+"); | |
91 | + if(dialogue==NULL){ perror("gestionClientHTTP.fdopen"); exit(-1); } | |
92 | + | |
93 | + char line[BUFFER_SIZE]; | |
94 | + char *success = fgets(line, BUFFER_SIZE, dialogue); | |
95 | + if(success == NULL){ | |
96 | + fclose(dialogue); | |
97 | + return; | |
98 | + } | |
99 | + | |
100 | + printf("Message recu :\n\n%s\n", line); | |
101 | + fprintf(dialogue, "Message recu :\n\n%s\n", line); | |
102 | + | |
103 | + fclose(dialogue); | |
104 | +} | |
105 | + | |
106 | +int main(void){ | |
107 | + // init serveur | |
108 | + char service[50] = "2030"; | |
109 | + int socket = initialisationServeurTCP(service); | |
110 | + | |
111 | + // lancement boucle infinie | |
112 | + boucleServeurTCP(socket, exemple_traitement); | |
113 | + | |
114 | + return 0; | |
115 | +} | |
0 | 116 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,29 @@ |
1 | +#include <stdio.h> | |
2 | +#include <pthread.h> | |
3 | + | |
4 | +void *print_hello(void *arg){ | |
5 | + (void) arg; // ici on utilise pas l'argument | |
6 | + printf("Hello\n"); | |
7 | + pthread_exit(NULL); | |
8 | +} | |
9 | + | |
10 | +void *print_nombre(void *arg){ | |
11 | + int n = *(int *) arg; // void* -> int* -> int | |
12 | + printf("Le nombre est :%d:\n", n); | |
13 | + pthread_exit(NULL); | |
14 | +} | |
15 | + | |
16 | +int main(void){ | |
17 | + pthread_t tid1, tid2; | |
18 | + // thread 1 | |
19 | + pthread_create(&tid1, NULL, print_hello, NULL); | |
20 | + pthread_detach(tid1); | |
21 | + | |
22 | + //thread 2 | |
23 | + int arg = 15; | |
24 | + pthread_create(&tid2, NULL, print_nombre, (void *) &arg); // int -> int* -> void* | |
25 | + pthread_detach(tid2); | |
26 | + | |
27 | + printf("Je peux terminer le thread principal sans avoir à attendre les deux autre en mode détaché\n"); | |
28 | + pthread_exit(NULL); | |
29 | +} | |
0 | 30 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,35 @@ |
1 | +#include <stdio.h> | |
2 | +#include <pthread.h> | |
3 | + | |
4 | +void *print_hello(void *arg){ | |
5 | + (void) arg; // ici on utilise pas l'argument | |
6 | + printf("Hello\n"); | |
7 | + pthread_exit(NULL); | |
8 | +} | |
9 | + | |
10 | +void *print_nombre(void *arg){ | |
11 | + int n = *(int *) arg; // void* -> int* -> int | |
12 | + printf("Le nombre est :%d:\n", n); | |
13 | + pthread_exit(NULL); | |
14 | +} | |
15 | + | |
16 | +int main(void){ | |
17 | + pthread_t tid1, tid2; | |
18 | + // thread 1 | |
19 | + pthread_create(&tid1, NULL, print_hello, NULL); | |
20 | + | |
21 | + //thread 2 | |
22 | + int arg = 15; | |
23 | + pthread_create(&tid2, NULL, print_nombre, (void *) &arg); // int -> int* -> void* | |
24 | + | |
25 | + // join thread 1 | |
26 | + pthread_join(tid1, NULL); | |
27 | + printf("Thread 1 terminé\n"); | |
28 | + | |
29 | + // join thread 2 | |
30 | + pthread_join(tid2, NULL); | |
31 | + printf("Thread 2 terminé\n"); | |
32 | + | |
33 | + printf("Je suis obligé de joindre les Threads pour les attendre en mode non-détaché\n"); | |
34 | + pthread_exit(NULL); | |
35 | +} | |
0 | 36 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,36 @@ |
1 | +#include <stdio.h> | |
2 | +#include <pthread.h> | |
3 | + | |
4 | +struct deux_int { | |
5 | + int a; | |
6 | + int b; | |
7 | +}; | |
8 | + | |
9 | +void *print_hello(void *arg){ | |
10 | + (void) arg; // ici on utilise pas l'argument | |
11 | + printf("Hello\n"); | |
12 | + pthread_exit(NULL); | |
13 | +} | |
14 | + | |
15 | +void *print_nombre(void *arg){ | |
16 | + struct deux_int ints = *(struct deux_int *) arg; // void* -> struct deux_int* -> struct deux_int | |
17 | + printf("Les nombres sont :%d: et :%d:\n", ints.a, ints.b); | |
18 | + pthread_exit(NULL); | |
19 | +} | |
20 | + | |
21 | +int main(void){ | |
22 | + pthread_t tid1, tid2; | |
23 | + // thread 1 | |
24 | + pthread_create(&tid1, NULL, print_hello, NULL); | |
25 | + pthread_detach(tid1); | |
26 | + | |
27 | + //thread 2 | |
28 | + struct deux_int ints; | |
29 | + ints.a = 15; | |
30 | + ints.b = 7; | |
31 | + pthread_create(&tid2, NULL, print_nombre, (void *) &ints); // struct deux_int -> struct deux_int* -> void* | |
32 | + pthread_detach(tid2); | |
33 | + | |
34 | + printf("Je peux terminer le thread principal sans avoir à attendre les deux autre en mode détaché\n"); | |
35 | + pthread_exit(NULL); | |
36 | +} | |
0 | 37 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,114 @@ |
1 | +Note : à la différence du fork, un thread ne créer pas de nouveau processus. | |
2 | + | |
3 | +#include <pthread.h> | |
4 | + | |
5 | +--- Compilation /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ | |
6 | +Avec gcc il faut utiliser -l pthread | |
7 | + gcc <programme> -l pthread | |
8 | + | |
9 | +--- Fonction hôte du thread | |
10 | +C'est la fonction qui va être executer dans le thread, la forme est toujours : | |
11 | + void *start_routine(void * args){ | |
12 | + // ... | |
13 | + } | |
14 | + | |
15 | +--- Création du thread | |
16 | +fonction : | |
17 | + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); | |
18 | + thread : id du thread (généré par la fonction) | |
19 | + attr : attribu, (très, très) souvent NULL | |
20 | + start_routine : fonction a executer dans le thread | |
21 | + arg : les argument à passer à start_routine | |
22 | + | |
23 | +exemple : | |
24 | + pthread tid; //thread id | |
25 | + pthread_create(&tid, NULL, thread_fonction, NULL); | |
26 | + | |
27 | +--- Rejoindre un thread | |
28 | +Suspend le thread qui appel la fonction et attend la terminaison du thread en argument. | |
29 | +Un tread joinable (c'est le cas par défault) va attendre un pthread_join avant de libérer sa mémoire. Utiliser pthread_detach pour éviter ça. | |
30 | + | |
31 | +fonction : | |
32 | + int pthread_join(pthread_t thread, void **status); | |
33 | + thread : l'id du thread à attendre | |
34 | + status : code de retour du thread attendu (généré par la fonction) | |
35 | + | |
36 | +exemple : | |
37 | + pthread_join(tid, NULL); | |
38 | + | |
39 | +--- Détachement des threads | |
40 | +Le mode détaché permet de libérer la mémoire après la terminaison. Sinon, il aurait fallu utiliser pthread_join pour le même résultat. | |
41 | + | |
42 | +fonction : | |
43 | + int pthread_detach(pthread_t thread); | |
44 | + thread : l'id du tread à détacher | |
45 | + | |
46 | +exemple: | |
47 | + pthread_detach(tid); | |
48 | + | |
49 | +--- Terminaison des threads | |
50 | +Termine le thread qui appel la fonction. Si le thread était le dernier actif, le processus se termine. | |
51 | + | |
52 | +fonction : | |
53 | + void pthread_exit(void *status); | |
54 | + status : code de terminaison | |
55 | + | |
56 | +exemple : | |
57 | + pthread_exit(NULL); | |
58 | + | |
59 | +--- Les arguments des fonctions | |
60 | +Les arguments sont tous en void*. | |
61 | + | |
62 | +Pour faire passer un int (exemple) : | |
63 | + // -- coté création thread : int -> int* -> void* | |
64 | + int arg = 5; | |
65 | + // arg est int | |
66 | + // &arg est int* | |
67 | + // (void *) &arg est void* | |
68 | + pthread_create([...], (void *) &arg); | |
69 | + | |
70 | + // coté thread : void* -> int* -> int | |
71 | + void *arg; | |
72 | + // arg est void* | |
73 | + // (int *) arg est int* | |
74 | + // *((int *) arg) ou *(int *) arg est int | |
75 | + int n = *(int *) arg; | |
76 | + | |
77 | +Pour une chaine de char (exemple) : | |
78 | + // -- coté création thread : char* -> void* | |
79 | + char str[50]; | |
80 | + // str est char* | |
81 | + // (void *) str est void * | |
82 | + pthread_create([...], (void *) &str); | |
83 | + | |
84 | + // coté thread : void* -> char* | |
85 | + void *arg; | |
86 | + // arg est void* | |
87 | + // (char *) arg est char* | |
88 | + char *str = (char *) arg; | |
89 | + | |
90 | +Pour plusieur arguments, utiliser une structure (exemple) : | |
91 | + struct deux_int { | |
92 | + int a; | |
93 | + int b; | |
94 | + } | |
95 | + | |
96 | + // -- coté création thread : struct deux_int -> struct deux_int* -> void* | |
97 | + int a = 1; | |
98 | + int b = 3; | |
99 | + struct deux_int ints; | |
100 | + ints.a = a; | |
101 | + ints.b = b; | |
102 | + // ints est struct deux_int | |
103 | + // &ints est struct deux_int* | |
104 | + // (void *) &ints est void* | |
105 | + pthread_create([...], (void *) &ints); | |
106 | + | |
107 | + // coté thread : void* -> struct deux_int* -> struct deux_int | |
108 | + void *arg; | |
109 | + // arg est void* | |
110 | + // (struct deux_int *) arg est struct deux_int* | |
111 | + // *(struct deux_int *) arg est struct deux_int | |
112 | + struct deux_int ints = *(struct deux_int *) arg; | |
113 | + int a = ints.a; | |
114 | + int b = ints.b; | |
0 | 115 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,23 @@ |
1 | +#include <stdio.h> | |
2 | +#include <pthread.h> | |
3 | + | |
4 | +void *thread_fonction(void *arg){ | |
5 | + | |
6 | + // TODO thread code | |
7 | + | |
8 | + pthread_exit(NULL); | |
9 | +} | |
10 | + | |
11 | +int main(void){ | |
12 | + | |
13 | + // TODO initialisation ? | |
14 | + | |
15 | + // Création du Thread | |
16 | + pthread_t tid; | |
17 | + // TODO thread args ? | |
18 | + pthread_create(&tid, NULL, thread_fonction, /*args ici ->*/NULL); | |
19 | + // pthread_detach(tid); ou pthread_join(tid, NULL); ? | |
20 | + // (il en faut au moins un des deux et un seul des deux) | |
21 | + | |
22 | + // TODO suite du programme | |
23 | +} | |
0 | 24 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,76 @@ |
1 | +#include <stdio.h> | |
2 | +#include <string.h> // pour strlen() | |
3 | +#include <stdlib.h> // pour exit() | |
4 | +#include <sys/socket.h> | |
5 | +#include <netinet/in.h> | |
6 | +#include <netinet/ip.h> | |
7 | +#include <netinet/udp.h> | |
8 | +#include <arpa/inet.h> | |
9 | + | |
10 | +//Fonction permettant d'envoyer un message en broadcast | |
11 | +void sendUDPBroadcast(unsigned char *message, int taille_message, int port) { | |
12 | + int broadcast_enable = 1; | |
13 | + //Option broadcast ON | |
14 | + int s = socket(AF_INET, SOCK_DGRAM, 0); | |
15 | + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) | |
16 | + if(s < 0){ | |
17 | + //Test de la valeur de retour de la socket | |
18 | + perror("sendUDPBroadcast.socket"); | |
19 | + exit(-1); | |
20 | + } | |
21 | + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable)) < 0) { | |
22 | + //Mise option broadcast à la socket | |
23 | + perror("sendUDPBroadcast.setsockopt"); | |
24 | + exit(-1); | |
25 | + } | |
26 | + | |
27 | + struct sockaddr_in broadcast_address; | |
28 | + memset(&broadcast_address, 0, sizeof(broadcast_address)); | |
29 | + broadcast_address.sin_family = AF_INET; | |
30 | + broadcast_address.sin_port = htons(port); | |
31 | + broadcast_address.sin_addr.s_addr = INADDR_BROADCAST; //255.255.255.255 | |
32 | + | |
33 | + //Envoie du message grâce à la socket | |
34 | + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &broadcast_address, | |
35 | + sizeof(broadcast_address)) < 0 ) { | |
36 | + perror("sendUDPBroadcast.sendto"); | |
37 | + exit(-1); | |
38 | + } | |
39 | +} | |
40 | + | |
41 | +//Fonction permettant d'envoyer un message à une adresse | |
42 | +void sendUDPUnicast(char *address, unsigned char *message, int taille_message, int port) { | |
43 | + int s = socket(AF_INET, SOCK_DGRAM, 0); | |
44 | + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) | |
45 | + if(s < 0){ | |
46 | + //Test de la valeur de retour de la socket | |
47 | + perror("sendUDPUnicast.socket"); | |
48 | + exit(-1); | |
49 | + } | |
50 | + struct sockaddr_in unicast_address; | |
51 | + //Creation structure adresse de destination | |
52 | + memset(&unicast_address, 0, sizeof(unicast_address)); | |
53 | + //Mise à zéro de la structure d'adresse | |
54 | + unicast_address.sin_family = AF_INET; | |
55 | + unicast_address.sin_port = htons(port); | |
56 | + //Mise du port en ordre du réseau (big endian) | |
57 | + unicast_address.sin_addr.s_addr = inet_addr(address); | |
58 | + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &unicast_address, sizeof(unicast_address)) < 0 ) { | |
59 | + perror("sendUDPUnicast.sendto"); | |
60 | + exit(-1); | |
61 | + } | |
62 | +} | |
63 | + | |
64 | +int main(void){ | |
65 | + unsigned char message_broadcast[100] = "J'envoie en UDP boradcast"; | |
66 | + unsigned char message_unicast[100] = "J'envoie en UDP unicast"; | |
67 | + | |
68 | + // send broadcast | |
69 | + sendUDPBroadcast(message_broadcast, strlen(message_broadcast), 2030); | |
70 | + | |
71 | + // send unicast | |
72 | + char adresse[50] = "127.0.0.1"; | |
73 | + sendUDPUnicast(adresse, message_unicast, strlen(message_unicast), 2030); | |
74 | + | |
75 | + return 0; | |
76 | +} | |
0 | 77 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,87 @@ |
1 | +#include <stdio.h> | |
2 | +#include <stdlib.h> // pour exit() | |
3 | +#include <string.h> | |
4 | +#include <sys/types.h> | |
5 | +#include <sys/socket.h> | |
6 | +#include <netinet/in.h> | |
7 | +#include <netinet/ip.h> | |
8 | +#include <netinet/udp.h> | |
9 | +#include <netdb.h> | |
10 | + | |
11 | +#define BUFFER_SIZE 1000 | |
12 | + | |
13 | +// Creation d'un serveur UDP | |
14 | +// service est le numéro ou nom de port (ex: "80" ou "http") | |
15 | +int initialisationServeurUDP(char *service){ | |
16 | + struct addrinfo precisions, *resultat, *origine; | |
17 | + int statut; | |
18 | + int s; | |
19 | + | |
20 | + /* Construction de la structure adresse */ | |
21 | + memset(&precisions, 0, sizeof precisions); | |
22 | + precisions.ai_family = AF_UNSPEC; | |
23 | + precisions.ai_socktype = SOCK_DGRAM; | |
24 | + precisions.ai_flags = AI_PASSIVE; | |
25 | + statut = getaddrinfo(NULL, service, &precisions, &origine); | |
26 | + if(statut < 0){ perror("initialisationSocketUDP.getaddrinfo"); exit(EXIT_FAILURE); } | |
27 | + | |
28 | + struct addrinfo *p; | |
29 | + for(p=origine, resultat=origine; p!=NULL; p=p->ai_next) | |
30 | + if(p->ai_family == AF_INET6){ resultat=p; break; } | |
31 | + | |
32 | + /* Creation d'une socket */ | |
33 | + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); | |
34 | + if(s<0){ perror("initialisationSocketUDP.socket"); exit(EXIT_FAILURE); } | |
35 | + | |
36 | + /* Options utiles */ | |
37 | + int vrai = 1; | |
38 | + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai)) < 0){ | |
39 | + perror("initialisationServeurUDPgenerique.setsockopt (REUSEADDR)"); | |
40 | + exit(-1); | |
41 | + } | |
42 | + | |
43 | + /* Specification de l'adresse de la socket */ | |
44 | + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); | |
45 | + if(statut < 0) { perror("initialisationServeurUDP.bind"); exit(-1); } | |
46 | + | |
47 | + /* Liberation de la structure d'informations */ | |
48 | + freeaddrinfo(origine); | |
49 | + | |
50 | + return s; | |
51 | +} | |
52 | + | |
53 | +// Reception des messages UDP et execute la fonction passee en argument | |
54 | +// ATTENTION : non multi-threadé ! -> il faut un pthread_create dans traitement pour le multi-thread. | |
55 | +int boucleServeurUDP(int s, void (*traitement)(unsigned char *, int)){ | |
56 | + while(1){ | |
57 | + struct sockaddr_storage adresse; | |
58 | + struct sockaddr *padresse = (struct sockaddr *) &adresse; | |
59 | + socklen_t taille = sizeof(adresse); | |
60 | + unsigned char message[BUFFER_SIZE]; | |
61 | + | |
62 | + int nboctets = recvfrom(s, message, BUFFER_SIZE, 0, (struct sockaddr *) padresse, &taille); | |
63 | + if(nboctets < 0) return -1; | |
64 | + | |
65 | + message[nboctets] = '\0'; | |
66 | + | |
67 | + traitement(message, nboctets); | |
68 | + } | |
69 | + return 0; | |
70 | +} | |
71 | + | |
72 | +void exemple_traitement(unsigned char *message, int length){ | |
73 | + (void) length; // on utilise pas length ici | |
74 | + | |
75 | + printf("Message recu :\n\n%s\n", message); | |
76 | +} | |
77 | + | |
78 | +int main(void){ | |
79 | + // init serveur | |
80 | + char service[50] = "2030"; | |
81 | + int socket = initialisationServeurUDP(service); | |
82 | + | |
83 | + // lancement boucle infinie | |
84 | + boucleServeurUDP(socket, exemple_traitement); | |
85 | + | |
86 | + return 0; | |
87 | +} | |
0 | 88 | \ No newline at end of file | ... | ... |