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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 | \ No newline at end of file | 31 | \ No newline at end of file |
@@ -0,0 +1,41 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 | \ No newline at end of file | 21 | \ No newline at end of file |
@@ -0,0 +1,78 @@ | @@ -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 | \ No newline at end of file | 79 | \ No newline at end of file |
@@ -0,0 +1,14 @@ | @@ -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 | \ No newline at end of file | 15 | \ No newline at end of file |
@@ -0,0 +1,74 @@ | @@ -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 | \ No newline at end of file | 75 | \ No newline at end of file |
@@ -0,0 +1,115 @@ | @@ -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 | \ No newline at end of file | 116 | \ No newline at end of file |
@@ -0,0 +1,29 @@ | @@ -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 | \ No newline at end of file | 30 | \ No newline at end of file |
@@ -0,0 +1,35 @@ | @@ -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 | \ No newline at end of file | 36 | \ No newline at end of file |
@@ -0,0 +1,36 @@ | @@ -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 | \ No newline at end of file | 37 | \ No newline at end of file |
@@ -0,0 +1,114 @@ | @@ -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 | \ No newline at end of file | 115 | \ No newline at end of file |
@@ -0,0 +1,23 @@ | @@ -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 | \ No newline at end of file | 24 | \ No newline at end of file |
@@ -0,0 +1,76 @@ | @@ -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 | \ No newline at end of file | 77 | \ No newline at end of file |
@@ -0,0 +1,87 @@ | @@ -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 | \ No newline at end of file | 88 | \ No newline at end of file |