diff --git a/Debug/Makefile b/Debug/Makefile new file mode 100644 index 0000000..1a5f065 --- /dev/null +++ b/Debug/Makefile @@ -0,0 +1,11 @@ +# C'est un exemple, il n'y a pas de source à compiler +CFLAGS=-I ../libs -lpthread -L ../libs -Wall -Wextra + +all: + gcc *.c -o main.out $(CFLAGS) + +debug: CFLAGS += -g -DDEBUG +debug: all + +clean: + rm -rf *.o *.out diff --git a/Debug/Mémo.txt b/Debug/Mémo.txt new file mode 100644 index 0000000..8563540 --- /dev/null +++ b/Debug/Mémo.txt @@ -0,0 +1,16 @@ +Les balises de débug servent a imprimer des infos suplémentaires en cas de besoin, sans qu'elles apparaissent dans le programme final. + +--- Dans le code : +#ifdef DEBUG + printf("Je ne print que quand DEBUG est définit\n"); +#endif + +--- Dans le make (activation du mode DEBUG) +debug: CFLAGS += -g -DDEBUG +debug: all + +explication : + CFLAGS sont les drapeaux passé à gcc (contien des choses comme -lpthread ou autre) + On y rajoute -g, pour que gcc nous affiche plus d'information sur la compilation + On y rajoute -DDEBUG, -D permet d'ajouter une balise (comme si on avait fait une #define DEBUG) + DEBUG est défini donc, les messages se print. diff --git a/Librairies/Exemple/Network/Makefile b/Librairies/Exemple/Network/Makefile new file mode 100644 index 0000000..ca48b59 --- /dev/null +++ b/Librairies/Exemple/Network/Makefile @@ -0,0 +1,26 @@ +TARGET=libnet +DIR_TARGET=../libs +CFLAGS=-Wall -pedantic -Wextra -I $(DIR_TARGET) +CLIB=ar cq +CC=gcc + +all: $(TARGET).a + +debug: CFLAGS += -g -DDEBUG +debug: all + +clean: + rm -f *.o *.a + rm -f $(DIR_TARGET)/$(TARGET).a + rm -f $(DIR_TARGET)/$(TARGET).h + +$(TARGET).o: $(TARGET).c $(TARGET).h + $(CC) -c $(CFLAGS) -o $@ $< + +$(TARGET).a: $(TARGET).o + rm -rf $@ + $(CLIB) $@ $+ + mkdir $(DIR_TARGET) -p + cp $(TARGET).a $(DIR_TARGET)/$(TARGET).a + cp $(TARGET).h $(DIR_TARGET)/$(TARGET).h + diff --git a/Librairies/Exemple/Network/libnet.c b/Librairies/Exemple/Network/libnet.c new file mode 100644 index 0000000..fcd76c7 --- /dev/null +++ b/Librairies/Exemple/Network/libnet.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_TCP_CONNEXION 10 +#define BUFFER_SIZE 1024 + +//Fonction permettant d'envoyer en broadcast un message +void sendUDPBroadcast(unsigned char *message, int taille_message, int port) { + int broadcast_enable = 1; + //Option broadcast ON + int s = socket(AF_INET, SOCK_DGRAM, 0); + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) + if(s < 0){ + //Test de la valeur de retour de la socket + perror("sendUDPBroadcast.socket"); + exit(-1); + } + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable)) < 0) { + //Mise option broadcast à la socket + perror("sendUDPBroadcast.setsockopt"); + exit(-1); + } + + struct sockaddr_in broadcast_address; + memset(&broadcast_address, 0, sizeof(broadcast_address)); + broadcast_address.sin_family = AF_INET; + broadcast_address.sin_port = htons(port); + broadcast_address.sin_addr.s_addr = INADDR_BROADCAST; //255.255.255.255 + + //Envoie du message grâce à la socket + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &broadcast_address, + sizeof(broadcast_address)) < 0 ) { + perror("sendUDPBroadcast.sendto"); + exit(-1); + } +} + + +void sendUDPUnicast(char *address, unsigned char *message, int taille_message, int port) { + int s = socket(AF_INET, SOCK_DGRAM, 0); + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) + if(s < 0){ + //Test de la valeur de retour de la socket + perror("sendUDPUnicast.socket"); + exit(-1); + } + struct sockaddr_in unicast_address; + //Creation structure adresse de destination + memset(&unicast_address, 0, sizeof(unicast_address)); + //Mise à zéro de la structure d'adresse + unicast_address.sin_family = AF_INET; + unicast_address.sin_port = htons(port); + //Mise du port en ordre du réseau (big endian) + unicast_address.sin_addr.s_addr = inet_addr(address); + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &unicast_address, sizeof(unicast_address)) < 0 ) { + perror("sendUDPUnicast.sendto"); + exit(-1); + } +} + +// Retourne l'adresse ip d'une connexion active +static int socketVersNomUDP(struct sockaddr *padresse, char *nom){ + void *ip; + int taille_nom; + if(padresse->sa_family == AF_INET){ + struct sockaddr_in *ipv4 = (struct sockaddr_in *) padresse; + ip = (void *) &ipv4->sin_addr; + taille_nom = INET_ADDRSTRLEN; + } + if(padresse->sa_family == AF_INET6){ + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) padresse; + ip = (void *)&ipv6->sin6_addr; + taille_nom = INET6_ADDRSTRLEN; + } + char nom_deco[20]; + inet_ntop(padresse->sa_family, ip, nom_deco, taille_nom); + sprintf(nom, "%s", nom_deco + 7); + return 0; +} +static int socketVersNomTCP(int s, char *nom){ + struct sockaddr_storage adresse; + struct sockaddr *padresse = (struct sockaddr *) &adresse; + socklen_t taille = sizeof adresse; + int statut; + + /* Recupere l'adresse de la socket distante */ + statut = getpeername(s, padresse, &taille); + if(statut<0){ + perror("socketVersNom.getpeername"); + return -1; + } + + /* Recupere le nom de la machine */ + return socketVersNomUDP(padresse, nom); +} + +// Fonction permettant de créer le serveur TCP +int initialisationServeurTCP(char *service){ + struct addrinfo precisions, *resultat, *origine; + int statut; + int s; + + /* Construction de la structure adresse */ + memset(&precisions, 0, sizeof precisions); + precisions.ai_family = AF_UNSPEC; + precisions.ai_socktype = SOCK_STREAM; + precisions.ai_flags = AI_PASSIVE; + statut = getaddrinfo(NULL, service, &precisions, &origine); + if(statut < 0){ + perror("initialisationSocketUDP.getaddrinfo"); + exit(EXIT_FAILURE); + } + struct addrinfo *p; + for(p = origine, resultat = origine; p != NULL; p = p->ai_next) { + if(p->ai_family == AF_INET6){ + resultat = p; + break; + } + } + + /* Creation d'une socket */ + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); + if(s < 0){ + perror("initialisationSocketUDP.socket"); + exit(EXIT_FAILURE); + } + + /* Options utiles */ + int vrai = 1; + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai))<0) { + perror("initialisationServeurUDPgenerique.setsockopt (REUSEADDR)"); + exit(-1); + } + + /* Specification de l'adresse de la socket */ + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); + if(statut<0) { + perror("initialisationServeurUDP.bind"); + exit(-1); + } + + /* Liberation de la structure d'informations */ + freeaddrinfo(origine); + + /* Taille de la queue d'attente */ + statut = listen(s, MAX_TCP_CONNEXION); + if(statut < 0) + return -1; + return s; +} + +// Accepte toutes les connexions au serveur TCP et execute la fonction en argument +int boucleServeurTCP(int socket, void (*traitement)(int, char *)){ + while(1){ + // accept connection + struct sockaddr ip_src; + socklen_t ip_len = sizeof(struct sockaddr); + int socket_dialogue = accept(socket, &ip_src, &ip_len); + if(socket_dialogue < 0){ + perror("boucleServeur.accept"); + return -1; + } + + // get ip addr + char char_ip[20]; + int status = socketVersNomTCP(socket_dialogue, char_ip); + if(status < 0) + perror("socketVersNom"); + + // callback function + traitement(socket_dialogue, char_ip); + } + return 0; +} + +// Creation d'un serveur UDP +int initialisationServeurUDP(char *service){ + struct addrinfo precisions, *resultat, *origine; + int statut; + int s; + + /* Construction de la structure adresse */ + memset(&precisions, 0, sizeof precisions); + precisions.ai_family = AF_UNSPEC; + precisions.ai_socktype = SOCK_DGRAM; + precisions.ai_flags = AI_PASSIVE; + statut = getaddrinfo(NULL, service, &precisions, &origine); + if(statut < 0){ perror("initialisationSocketUDP.getaddrinfo"); exit(EXIT_FAILURE); } + + struct addrinfo *p; + for(p=origine, resultat=origine; p!=NULL; p=p->ai_next) + if(p->ai_family == AF_INET6){ resultat=p; break; } + + /* Creation d'une socket */ + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); + if(s<0){ perror("initialisationSocketUDP.socket"); exit(EXIT_FAILURE); } + + /* Options utiles */ + int vrai = 1; + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai)) < 0){ + perror("initialisationServeurUDPgenerique.setsockopt (REUSEADDR)"); + exit(-1); + } + + /* Specification de l'adresse de la socket */ + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); + if(statut < 0) { perror("initialisationServeurUDP.bind"); exit(-1); } + + /* Liberation de la structure d'informations */ + freeaddrinfo(origine); + + return s; +} + +// Reception des messages UDP et execute la fonction passee en argument +int boucleServeurUDP(int s, void (*traitement)(unsigned char *, int, char *)){ + while(1){ + struct sockaddr_storage adresse; + struct sockaddr *padresse = (struct sockaddr *) &adresse; + socklen_t taille = sizeof(adresse); + unsigned char message[BUFFER_SIZE]; + + int nboctets = recvfrom(s, message, BUFFER_SIZE, 0, (struct sockaddr *) padresse, &taille); + if(nboctets < 0) return -1; + + /* Recupere le nom de la machine */ + char char_ip[20]; + int status = socketVersNomUDP(padresse, char_ip); + if(status < 0) + perror("socketVersNom"); + + traitement(message, nboctets, char_ip); + } + return 0; +} + +// Initialise un client TCP +int openTCPClient(char *hote, int port) { + int s; + struct sockaddr_in adresse; + socklen_t taille = sizeof adresse; + + // creation socket + s = socket(PF_INET, SOCK_STREAM, 0); + if(s<0){ perror("connexionServeur.socket"); exit(-1); } + + // connexion + memset(&adresse, 0, sizeof(adresse)); + adresse.sin_family=AF_INET; + adresse.sin_port = htons(port); + adresse.sin_addr.s_addr = inet_addr(hote); + if(connect(s,(struct sockaddr *)&adresse, taille)<0) return -1; + return s; +} + +// Envoie un message TCP sur une connexion active +void sendTCP(int socket, char *message, int length_message){ + if(length_message <= 0) + return; + write(socket, message, length_message); +} + +// Recois un message TCP sur une connexion active +int receiveTCP(int socket, char *message, int max_length){ + return read(socket, message, max_length); +} diff --git a/Librairies/Exemple/Network/libnet.h b/Librairies/Exemple/Network/libnet.h new file mode 100644 index 0000000..c369f08 --- /dev/null +++ b/Librairies/Exemple/Network/libnet.h @@ -0,0 +1,19 @@ +#ifndef LIBNET_H +#define LIBNET_H + +#include + +int sendUDPBroadcast(unsigned char *message, int taille_message, int port); +int sendUDPUnicast(char *address, unsigned char *message, int taille_message, int port); + +int initialisationServeurTCP(char *service); +int boucleServeurTCP(int socket, void (*traitement)(int, char *)); + +int initialisationServeurUDP(char *service); +int boucleServeurUDP(int s, void (*traitement)(unsigned char *, int, char *)); + +int openTCPClient(char *hote, int port); +void sendTCP(int socket, char *message, int length_message); +int receiveTCP(int socket, char *message, int max_length); + +#endif diff --git a/Librairies/Exemple/libs/libnet.a b/Librairies/Exemple/libs/libnet.a new file mode 100644 index 0000000..34e243d Binary files /dev/null and b/Librairies/Exemple/libs/libnet.a differ diff --git a/Librairies/Makefile b/Librairies/Makefile new file mode 100644 index 0000000..382e1f5 --- /dev/null +++ b/Librairies/Makefile @@ -0,0 +1,25 @@ +TARGET=toto +DIR_TARGET=./toto_lib +CFLAGS=-Wall -pedantic -Wextra -I $(DIR_TARGET) +CLIB=ar cq +CC=gcc + +all: $(TARGET).a + +debug: CFLAGS += -g -DDEBUG +debug: all + +clean: + rm -f *.o *.a + rm -f $(DIR_TARGET)/$(TARGET).a + rm -f $(DIR_TARGET)/$(TARGET).h + +$(TARGET).o: $(TARGET).c $(TARGET).h + $(CC) -c $(CFLAGS) -o $@ $< + +$(TARGET).a: $(TARGET).o + rm -rf $@ + $(CLIB) $@ $+ + mkdir $(DIR_TARGET) -p + cp $(TARGET).a $(DIR_TARGET)/$(TARGET).a + cp $(TARGET).h $(DIR_TARGET)/$(TARGET).h diff --git a/Librairies/Mémo.txt b/Librairies/Mémo.txt new file mode 100644 index 0000000..f153fc7 --- /dev/null +++ b/Librairies/Mémo.txt @@ -0,0 +1,30 @@ +Une librairie (un .a) est construit à partir de .o + Rappel générer un .o : gcc -c + +Nom d'une librairie : TOUJOURS lib_____.a + +Création : + ar cq +"q" permet la création de la librairie (pour les options taper ar dans le terminal) + +Attention : il faut aussi donner le .h avec le .a + +Utilisation d'une librairie : + - #include <_____.h> + - gcc [...] -L -I + +Utilisation du squelette Makefile : + - remplacer "toto" par la cible (ex: libnet) + - remplacer "./toto_lib" par le dossier qui contiendra la librairie (ex: ../libs) + +Ce que fait le make (make all) : + - compile le TARGET.c en .o + - crée la librairie .a + - copie .a et .h dans le dossier DIR_TRAGET + +Ce que fait le make clean : + - efface le .o et le .a dans ./ + - efface le .a et le .h du dossier DIR_TRAGET + +Ce que fait le make debug : + (voir la partie sur les flags de debug dans ../Debug) \ No newline at end of file diff --git a/Multi_Makefiles/Makefile b/Multi_Makefiles/Makefile new file mode 100644 index 0000000..3a1bfcf --- /dev/null +++ b/Multi_Makefiles/Makefile @@ -0,0 +1,41 @@ +# +# Variables d'environnement +# +export CC = gcc +export LD = gcc +export CLIB = ar cq +export CFLAGS = -Wall -Wextra -pedantic + +# +# Constantes liees au projet +# + +DIRS = Threads Network Sioux Tangible + +# +# La cible generale +# + +all: $(patsubst %, _dir_%, $(DIRS)) + +$(patsubst %,_dir_%,$(DIRS)): + cd $(patsubst _dir_%,%,$@) && make + +# +# La cible de debug +# + +debug: CFLAGS += -g -DDEBUG +debug: $(patsubst %, _debug_%, $(DIRS)) + +$(patsubst %,_debug_%,$(DIRS)): + cd $(patsubst _debug_%,%,$@) && make debug + +# +# La cible de nettoyage +# + +clean: $(patsubst %, _clean_%, $(DIRS)) + +$(patsubst %,_clean_%,$(DIRS)): + cd $(patsubst _clean_%,%,$@) && make clean diff --git a/Multi_Makefiles/Mémo.txt b/Multi_Makefiles/Mémo.txt new file mode 100644 index 0000000..67de545 --- /dev/null +++ b/Multi_Makefiles/Mémo.txt @@ -0,0 +1,18 @@ +Appeler un makefile depuis un makefile "maitre". + +Dans les makefiles "esclaves", créer les cibles que va appeler le makefile "maitre" (all, clean, debug, etc...) + +Pour les appeler à partir du makefile maitre : (ex avec clean) + +clean: $(patsubst %, _clean_%, $(DIRS)) +$(patsubst %,_clean_%,$(DIRS)): + cd $(patsubst _clean_%,%,$@) && make clean + +Ce que fait la focntion plus haut : + - parmis la liste des dossiers donné dans la variable DIRS + - fait un cd au dossier + - fait un make clean + +Les variables d'environnement (export CC, etc...) ne sont pas obligatoire mais permettent d'unifier les plus communes. +Exemple : dans le makefile "eclave" $(CC), n'est pas définit mais le makefile "maitre" le définit avec un export CC=gcc. + diff --git a/Signaux/Exemple/Makefile b/Signaux/Exemple/Makefile new file mode 100644 index 0000000..b56e968 --- /dev/null +++ b/Signaux/Exemple/Makefile @@ -0,0 +1,9 @@ + +all: + gcc main.c -o main.out + +exec: all + ./main.out + +clean: + rm -rf *.o *.out \ No newline at end of file diff --git a/Signaux/Exemple/main.c b/Signaux/Exemple/main.c new file mode 100644 index 0000000..0ac3458 --- /dev/null +++ b/Signaux/Exemple/main.c @@ -0,0 +1,20 @@ +#include +#include // pour exit(0); +#include // pour sleep(1); +#include + +/** Fonction appelé lors de la reception du signal */ +void handler(int sig){ + printf("Signal reçu :%d:", sig); + exit(0); +} + +int main(void){ + // à mettre en début de main + struct sigaction action; + action.sa_handler = handler; + sigaction(SIGINT, &action, NULL); // On écoute le signal SIGINT (CTRL+C) + + // attente / à remplacer par la suite + while(1) sleep(1); +} \ No newline at end of file diff --git a/Signaux/Mémo.txt b/Signaux/Mémo.txt new file mode 100644 index 0000000..313488e --- /dev/null +++ b/Signaux/Mémo.txt @@ -0,0 +1,78 @@ +#include + +--- codes signaux +Signal CTRL+C = SIGINT (ou 2) + +codes complets : +(voir à la fin / pas très utile) + +--- Envoi de signaux : + int kill(pid_t pid, int sig); // pid_t ~= int + +pid : >0 processus précis + =0 processus dans le même groupe que notre processus + <0 tous les processus du groupe "-pid" + + +--- Reception de signaux : +Définition d'un handler (fonction appelé lors de la recpetion d'un signal) : + void handler(int sig){ + //... + } + +Enregistrement du handler dans sigaction : + struct sigaction action; + action.sa_handler; + +La fonction sigaction : + int sigaction(int sig_to_listen, const struct sigaction *sigaction, struct sigaction *sigaction_anc); //sigaction_anc = NULL (très, très) souvent + +Déclaration du sigaction pour détecter les signaux (ex: SIG_INT) : + sigaction(SIGINT, &action, NULL); + +--- Attendre un signal +la fonction : + int pause (void); + + +--- Commandes terminal utiles +voir la liste des processus : + ps / ps -a + +tuer un processus avec un signal particulier : + kill - / kill -s + Note : le signal 9 (kill -9 ) tue n'importe quel processus imédiatement + +--- Utilisation du squelette +Remplacer les balises "TODO" par les valeurs souhaitées + + + + +--- Tous les codes de signaux + +(venant de l'aide de la commande "man 7 signal") + +Signal Value Action Comment +────────────────────────────────────────────────────────────────────── +SIGHUP 1 Term Hangup detected on controlling terminal + or death of controlling process +SIGINT 2 Term Interrupt from keyboard +SIGQUIT 3 Core Quit from keyboard +SIGILL 4 Core Illegal Instruction +SIGABRT 6 Core Abort signal from abort(3) +SIGFPE 8 Core Floating-point exception +SIGKILL 9 Term Kill signal +SIGSEGV 11 Core Invalid memory reference +SIGPIPE 13 Term Broken pipe: write to pipe with no + readers; see pipe(7) +SIGALRM 14 Term Timer signal from alarm(2) +SIGTERM 15 Term Termination signal +SIGUSR1 30,10,16 Term User-defined signal 1 +SIGUSR2 31,12,17 Term User-defined signal 2 +SIGCHLD 20,17,18 Ign Child stopped or terminated +SIGCONT 19,18,25 Cont Continue if stopped +SIGSTOP 17,19,23 Stop Stop process +SIGTSTP 18,20,24 Stop Stop typed at terminal +SIGTTIN 21,21,26 Stop Terminal input for background process +SIGTTOU 22,22,27 Stop Terminal output for background process \ No newline at end of file diff --git a/Signaux/Squelette_signaux.c b/Signaux/Squelette_signaux.c new file mode 100644 index 0000000..c341b40 --- /dev/null +++ b/Signaux/Squelette_signaux.c @@ -0,0 +1,14 @@ +#include +#include + +void handler(int sig){ + //TODO code à executer à la recpetion du signal... +} + +int main(void){ + struct sigaction action; + action.sa_handler = handler; + sigaction(/*TODO signal à écouter...*/, &action, NULL); + + // TODO programme normal... +} \ No newline at end of file diff --git a/TCP/Client/Makefile b/TCP/Client/Makefile new file mode 100644 index 0000000..c4dea1a --- /dev/null +++ b/TCP/Client/Makefile @@ -0,0 +1,10 @@ + + +all: + gcc main.c -o main.out + +exec: all + ./main.out + +clean: + rm -rf *.o *.out \ No newline at end of file diff --git a/TCP/Client/main.c b/TCP/Client/main.c new file mode 100644 index 0000000..f4275ba --- /dev/null +++ b/TCP/Client/main.c @@ -0,0 +1,74 @@ +#include +#include // pour strlen() +#include // pour exit() +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1000 + +// Initialise un client TCP, retourne la socket creee +int openTCPClient(char *hote, int port) { + int s; + struct sockaddr_in adresse; + socklen_t taille = sizeof adresse; + + // creation socket + s = socket(PF_INET, SOCK_STREAM, 0); + if(s<0){ perror("connexionServeur.socket"); exit(-1); } + + // connexion + memset(&adresse, 0, sizeof(adresse)); + adresse.sin_family=AF_INET; + adresse.sin_port = htons(port); + adresse.sin_addr.s_addr = inet_addr(hote); + if(connect(s,(struct sockaddr *)&adresse, taille)<0) return -1; + return s; +} + +// Envoie un message TCP sur une connexion active +void sendTCP(int socket, char *message, int length_message){ + if(length_message <= 0) + return; + write(socket, message, length_message); +} + +// Recois un message TCP sur une connexion active. Retourne le nombre de char recu +int receiveTCP(int socket, char *message, int max_length){ + return read(socket, message, max_length); +} + +// Ferme le connection entre le serveur et le client +void closeTCPCLient(int socket){ + shutdown(socket, SHUT_RDWR); +} + +int main(void){ + char google_addr[50] = "172.217.7.163"; + + // Open connection + int socket = openTCPClient(google_addr, 80); + + // Send GET HTTP request test + char message[1000] = "GET / HTTP/1.1\n\n\0"; + sendTCP(socket, message, strlen(message)); + + // Recieve HTTP response + char rep[BUFFER_SIZE]; + int status = receiveTCP(socket, rep, BUFFER_SIZE); + if(status < 0){ + printf("Erreur de recieve\n"); + exit(-1); + } + + // affichage + printf("%s\n", rep); + + // déconnection + closeTCPCLient(socket); + + return 0; +} \ No newline at end of file diff --git a/TCP/Serveur/Makefile b/TCP/Serveur/Makefile new file mode 100644 index 0000000..c4dea1a --- /dev/null +++ b/TCP/Serveur/Makefile @@ -0,0 +1,10 @@ + + +all: + gcc main.c -o main.out + +exec: all + ./main.out + +clean: + rm -rf *.o *.out \ No newline at end of file diff --git a/TCP/Serveur/main.c b/TCP/Serveur/main.c new file mode 100644 index 0000000..a3c01d9 --- /dev/null +++ b/TCP/Serveur/main.c @@ -0,0 +1,115 @@ +#include +#include // pour exit() +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1000 +#define MAX_TCP_CONNEXION 5 + +// Fonction permettant de créer le serveur TCP +// service est le numéro ou nom de port (ex: "80" ou "http") +int initialisationServeurTCP(char *service){ + struct addrinfo precisions, *resultat, *origine; + int statut; + int s; + + /* Construction de la structure adresse */ + memset(&precisions, 0, sizeof precisions); + precisions.ai_family = AF_UNSPEC; + precisions.ai_socktype = SOCK_STREAM; + precisions.ai_flags = AI_PASSIVE; + statut = getaddrinfo(NULL, service, &precisions, &origine); + if(statut < 0){ + perror("initialisationSocketTCP.getaddrinfo"); + exit(EXIT_FAILURE); + } + struct addrinfo *p; + for(p = origine, resultat = origine; p != NULL; p = p->ai_next) { + if(p->ai_family == AF_INET6){ + resultat = p; + break; + } + } + + /* Creation d'une socket */ + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); + if(s < 0){ + perror("initialisationSocketTCP.socket"); + exit(EXIT_FAILURE); + } + + /* Options utiles */ + int vrai = 1; + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai))<0) { + perror("initialisationServeurTCPgenerique.setsockopt (REUSEADDR)"); + exit(-1); + } + + /* Specification de l'adresse de la socket */ + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); + if(statut<0) { + perror("initialisationServeurTCP.bind"); + exit(-1); + } + + /* Liberation de la structure d'informations */ + freeaddrinfo(origine); + + /* Taille de la queue d'attente */ + statut = listen(s, MAX_TCP_CONNEXION); + if(statut < 0) + return -1; + return s; +} + +// Accepte toutes les connexions au serveur TCP et execute la fonction en argument +// ATTENTION : non multi-threadé ! -> il faut un pthread_create dans traitement pour le multi-thread. +int boucleServeurTCP(int socket, void (*traitement)(int)){ + while(1){ + // accept connection + struct sockaddr ip_src; + socklen_t ip_len = sizeof(struct sockaddr); + int socket_dialogue = accept(socket, &ip_src, &ip_len); + if(socket_dialogue < 0){ + perror("boucleServeur.accept"); + return -1; + } + + // callback function + traitement(socket_dialogue); + } + return 0; +} + +void exemple_traitement(int socket){ + FILE *dialogue = fdopen(socket, "a+"); + if(dialogue==NULL){ perror("gestionClientHTTP.fdopen"); exit(-1); } + + char line[BUFFER_SIZE]; + char *success = fgets(line, BUFFER_SIZE, dialogue); + if(success == NULL){ + fclose(dialogue); + return; + } + + printf("Message recu :\n\n%s\n", line); + fprintf(dialogue, "Message recu :\n\n%s\n", line); + + fclose(dialogue); +} + +int main(void){ + // init serveur + char service[50] = "2030"; + int socket = initialisationServeurTCP(service); + + // lancement boucle infinie + boucleServeurTCP(socket, exemple_traitement); + + return 0; +} \ No newline at end of file diff --git a/Threads/Exemples/Detach/Makefile b/Threads/Exemples/Detach/Makefile new file mode 100644 index 0000000..fe6c4ef --- /dev/null +++ b/Threads/Exemples/Detach/Makefile @@ -0,0 +1,10 @@ +LIBS=-lpthread + +all: + gcc main.c -o main.out $(LIBS) + +exec: all + ./main.out + +clean: + rm -rf *.out *.o diff --git a/Threads/Exemples/Detach/main.c b/Threads/Exemples/Detach/main.c new file mode 100644 index 0000000..727ada2 --- /dev/null +++ b/Threads/Exemples/Detach/main.c @@ -0,0 +1,29 @@ +#include +#include + +void *print_hello(void *arg){ + (void) arg; // ici on utilise pas l'argument + printf("Hello\n"); + pthread_exit(NULL); +} + +void *print_nombre(void *arg){ + int n = *(int *) arg; // void* -> int* -> int + printf("Le nombre est :%d:\n", n); + pthread_exit(NULL); +} + +int main(void){ + pthread_t tid1, tid2; + // thread 1 + pthread_create(&tid1, NULL, print_hello, NULL); + pthread_detach(tid1); + + //thread 2 + int arg = 15; + pthread_create(&tid2, NULL, print_nombre, (void *) &arg); // int -> int* -> void* + pthread_detach(tid2); + + printf("Je peux terminer le thread principal sans avoir à attendre les deux autre en mode détaché\n"); + pthread_exit(NULL); +} \ No newline at end of file diff --git a/Threads/Exemples/Join/Makefile b/Threads/Exemples/Join/Makefile new file mode 100644 index 0000000..fe6c4ef --- /dev/null +++ b/Threads/Exemples/Join/Makefile @@ -0,0 +1,10 @@ +LIBS=-lpthread + +all: + gcc main.c -o main.out $(LIBS) + +exec: all + ./main.out + +clean: + rm -rf *.out *.o diff --git a/Threads/Exemples/Join/main.c b/Threads/Exemples/Join/main.c new file mode 100644 index 0000000..3b8894b --- /dev/null +++ b/Threads/Exemples/Join/main.c @@ -0,0 +1,35 @@ +#include +#include + +void *print_hello(void *arg){ + (void) arg; // ici on utilise pas l'argument + printf("Hello\n"); + pthread_exit(NULL); +} + +void *print_nombre(void *arg){ + int n = *(int *) arg; // void* -> int* -> int + printf("Le nombre est :%d:\n", n); + pthread_exit(NULL); +} + +int main(void){ + pthread_t tid1, tid2; + // thread 1 + pthread_create(&tid1, NULL, print_hello, NULL); + + //thread 2 + int arg = 15; + pthread_create(&tid2, NULL, print_nombre, (void *) &arg); // int -> int* -> void* + + // join thread 1 + pthread_join(tid1, NULL); + printf("Thread 1 terminé\n"); + + // join thread 2 + pthread_join(tid2, NULL); + printf("Thread 2 terminé\n"); + + printf("Je suis obligé de joindre les Threads pour les attendre en mode non-détaché\n"); + pthread_exit(NULL); +} \ No newline at end of file diff --git a/Threads/Exemples/Plusieur_args/Makefile b/Threads/Exemples/Plusieur_args/Makefile new file mode 100644 index 0000000..fe6c4ef --- /dev/null +++ b/Threads/Exemples/Plusieur_args/Makefile @@ -0,0 +1,10 @@ +LIBS=-lpthread + +all: + gcc main.c -o main.out $(LIBS) + +exec: all + ./main.out + +clean: + rm -rf *.out *.o diff --git a/Threads/Exemples/Plusieur_args/main.c b/Threads/Exemples/Plusieur_args/main.c new file mode 100644 index 0000000..7ec620e --- /dev/null +++ b/Threads/Exemples/Plusieur_args/main.c @@ -0,0 +1,36 @@ +#include +#include + +struct deux_int { + int a; + int b; +}; + +void *print_hello(void *arg){ + (void) arg; // ici on utilise pas l'argument + printf("Hello\n"); + pthread_exit(NULL); +} + +void *print_nombre(void *arg){ + struct deux_int ints = *(struct deux_int *) arg; // void* -> struct deux_int* -> struct deux_int + printf("Les nombres sont :%d: et :%d:\n", ints.a, ints.b); + pthread_exit(NULL); +} + +int main(void){ + pthread_t tid1, tid2; + // thread 1 + pthread_create(&tid1, NULL, print_hello, NULL); + pthread_detach(tid1); + + //thread 2 + struct deux_int ints; + ints.a = 15; + ints.b = 7; + pthread_create(&tid2, NULL, print_nombre, (void *) &ints); // struct deux_int -> struct deux_int* -> void* + pthread_detach(tid2); + + printf("Je peux terminer le thread principal sans avoir à attendre les deux autre en mode détaché\n"); + pthread_exit(NULL); +} \ No newline at end of file diff --git a/Threads/Mémo.txt b/Threads/Mémo.txt new file mode 100644 index 0000000..f3174d3 --- /dev/null +++ b/Threads/Mémo.txt @@ -0,0 +1,114 @@ +Note : à la différence du fork, un thread ne créer pas de nouveau processus. + +#include + +--- Compilation /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ +Avec gcc il faut utiliser -l pthread + gcc -l pthread + +--- Fonction hôte du thread +C'est la fonction qui va être executer dans le thread, la forme est toujours : + void *start_routine(void * args){ + // ... + } + +--- Création du thread +fonction : + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); + thread : id du thread (généré par la fonction) + attr : attribu, (très, très) souvent NULL + start_routine : fonction a executer dans le thread + arg : les argument à passer à start_routine + +exemple : + pthread tid; //thread id + pthread_create(&tid, NULL, thread_fonction, NULL); + +--- Rejoindre un thread +Suspend le thread qui appel la fonction et attend la terminaison du thread en argument. +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. + +fonction : + int pthread_join(pthread_t thread, void **status); + thread : l'id du thread à attendre + status : code de retour du thread attendu (généré par la fonction) + +exemple : + pthread_join(tid, NULL); + +--- Détachement des threads +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. + +fonction : + int pthread_detach(pthread_t thread); + thread : l'id du tread à détacher + +exemple: + pthread_detach(tid); + +--- Terminaison des threads +Termine le thread qui appel la fonction. Si le thread était le dernier actif, le processus se termine. + +fonction : + void pthread_exit(void *status); + status : code de terminaison + +exemple : + pthread_exit(NULL); + +--- Les arguments des fonctions +Les arguments sont tous en void*. + +Pour faire passer un int (exemple) : + // -- coté création thread : int -> int* -> void* + int arg = 5; + // arg est int + // &arg est int* + // (void *) &arg est void* + pthread_create([...], (void *) &arg); + + // coté thread : void* -> int* -> int + void *arg; + // arg est void* + // (int *) arg est int* + // *((int *) arg) ou *(int *) arg est int + int n = *(int *) arg; + +Pour une chaine de char (exemple) : + // -- coté création thread : char* -> void* + char str[50]; + // str est char* + // (void *) str est void * + pthread_create([...], (void *) &str); + + // coté thread : void* -> char* + void *arg; + // arg est void* + // (char *) arg est char* + char *str = (char *) arg; + +Pour plusieur arguments, utiliser une structure (exemple) : + struct deux_int { + int a; + int b; + } + + // -- coté création thread : struct deux_int -> struct deux_int* -> void* + int a = 1; + int b = 3; + struct deux_int ints; + ints.a = a; + ints.b = b; + // ints est struct deux_int + // &ints est struct deux_int* + // (void *) &ints est void* + pthread_create([...], (void *) &ints); + + // coté thread : void* -> struct deux_int* -> struct deux_int + void *arg; + // arg est void* + // (struct deux_int *) arg est struct deux_int* + // *(struct deux_int *) arg est struct deux_int + struct deux_int ints = *(struct deux_int *) arg; + int a = ints.a; + int b = ints.b; \ No newline at end of file diff --git a/Threads/Squelette_threads.c b/Threads/Squelette_threads.c new file mode 100644 index 0000000..4bd005e --- /dev/null +++ b/Threads/Squelette_threads.c @@ -0,0 +1,23 @@ +#include +#include + +void *thread_fonction(void *arg){ + + // TODO thread code + + pthread_exit(NULL); +} + +int main(void){ + + // TODO initialisation ? + + // Création du Thread + pthread_t tid; + // TODO thread args ? + pthread_create(&tid, NULL, thread_fonction, /*args ici ->*/NULL); + // pthread_detach(tid); ou pthread_join(tid, NULL); ? + // (il en faut au moins un des deux et un seul des deux) + + // TODO suite du programme +} \ No newline at end of file diff --git a/UDP/Client/Makefile b/UDP/Client/Makefile new file mode 100644 index 0000000..c4dea1a --- /dev/null +++ b/UDP/Client/Makefile @@ -0,0 +1,10 @@ + + +all: + gcc main.c -o main.out + +exec: all + ./main.out + +clean: + rm -rf *.o *.out \ No newline at end of file diff --git a/UDP/Client/main.c b/UDP/Client/main.c new file mode 100644 index 0000000..a508c6f --- /dev/null +++ b/UDP/Client/main.c @@ -0,0 +1,76 @@ +#include +#include // pour strlen() +#include // pour exit() +#include +#include +#include +#include +#include + +//Fonction permettant d'envoyer un message en broadcast +void sendUDPBroadcast(unsigned char *message, int taille_message, int port) { + int broadcast_enable = 1; + //Option broadcast ON + int s = socket(AF_INET, SOCK_DGRAM, 0); + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) + if(s < 0){ + //Test de la valeur de retour de la socket + perror("sendUDPBroadcast.socket"); + exit(-1); + } + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable)) < 0) { + //Mise option broadcast à la socket + perror("sendUDPBroadcast.setsockopt"); + exit(-1); + } + + struct sockaddr_in broadcast_address; + memset(&broadcast_address, 0, sizeof(broadcast_address)); + broadcast_address.sin_family = AF_INET; + broadcast_address.sin_port = htons(port); + broadcast_address.sin_addr.s_addr = INADDR_BROADCAST; //255.255.255.255 + + //Envoie du message grâce à la socket + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &broadcast_address, + sizeof(broadcast_address)) < 0 ) { + perror("sendUDPBroadcast.sendto"); + exit(-1); + } +} + +//Fonction permettant d'envoyer un message à une adresse +void sendUDPUnicast(char *address, unsigned char *message, int taille_message, int port) { + int s = socket(AF_INET, SOCK_DGRAM, 0); + //Création de la socket : s = file descriptor de la socket, AF_INET (socket internet), SOCK_DGRAM (datagramme, UDP, sans connexion) + if(s < 0){ + //Test de la valeur de retour de la socket + perror("sendUDPUnicast.socket"); + exit(-1); + } + struct sockaddr_in unicast_address; + //Creation structure adresse de destination + memset(&unicast_address, 0, sizeof(unicast_address)); + //Mise à zéro de la structure d'adresse + unicast_address.sin_family = AF_INET; + unicast_address.sin_port = htons(port); + //Mise du port en ordre du réseau (big endian) + unicast_address.sin_addr.s_addr = inet_addr(address); + if(sendto(s, message, taille_message, 0, (struct sockaddr *) &unicast_address, sizeof(unicast_address)) < 0 ) { + perror("sendUDPUnicast.sendto"); + exit(-1); + } +} + +int main(void){ + unsigned char message_broadcast[100] = "J'envoie en UDP boradcast"; + unsigned char message_unicast[100] = "J'envoie en UDP unicast"; + + // send broadcast + sendUDPBroadcast(message_broadcast, strlen(message_broadcast), 2030); + + // send unicast + char adresse[50] = "127.0.0.1"; + sendUDPUnicast(adresse, message_unicast, strlen(message_unicast), 2030); + + return 0; +} \ No newline at end of file diff --git a/UDP/Serveur/Makefile b/UDP/Serveur/Makefile new file mode 100644 index 0000000..c4dea1a --- /dev/null +++ b/UDP/Serveur/Makefile @@ -0,0 +1,10 @@ + + +all: + gcc main.c -o main.out + +exec: all + ./main.out + +clean: + rm -rf *.o *.out \ No newline at end of file diff --git a/UDP/Serveur/main.c b/UDP/Serveur/main.c new file mode 100644 index 0000000..c3d5117 --- /dev/null +++ b/UDP/Serveur/main.c @@ -0,0 +1,87 @@ +#include +#include // pour exit() +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1000 + +// Creation d'un serveur UDP +// service est le numéro ou nom de port (ex: "80" ou "http") +int initialisationServeurUDP(char *service){ + struct addrinfo precisions, *resultat, *origine; + int statut; + int s; + + /* Construction de la structure adresse */ + memset(&precisions, 0, sizeof precisions); + precisions.ai_family = AF_UNSPEC; + precisions.ai_socktype = SOCK_DGRAM; + precisions.ai_flags = AI_PASSIVE; + statut = getaddrinfo(NULL, service, &precisions, &origine); + if(statut < 0){ perror("initialisationSocketUDP.getaddrinfo"); exit(EXIT_FAILURE); } + + struct addrinfo *p; + for(p=origine, resultat=origine; p!=NULL; p=p->ai_next) + if(p->ai_family == AF_INET6){ resultat=p; break; } + + /* Creation d'une socket */ + s = socket(resultat->ai_family, resultat->ai_socktype, resultat->ai_protocol); + if(s<0){ perror("initialisationSocketUDP.socket"); exit(EXIT_FAILURE); } + + /* Options utiles */ + int vrai = 1; + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai)) < 0){ + perror("initialisationServeurUDPgenerique.setsockopt (REUSEADDR)"); + exit(-1); + } + + /* Specification de l'adresse de la socket */ + statut = bind(s, resultat->ai_addr, resultat->ai_addrlen); + if(statut < 0) { perror("initialisationServeurUDP.bind"); exit(-1); } + + /* Liberation de la structure d'informations */ + freeaddrinfo(origine); + + return s; +} + +// Reception des messages UDP et execute la fonction passee en argument +// ATTENTION : non multi-threadé ! -> il faut un pthread_create dans traitement pour le multi-thread. +int boucleServeurUDP(int s, void (*traitement)(unsigned char *, int)){ + while(1){ + struct sockaddr_storage adresse; + struct sockaddr *padresse = (struct sockaddr *) &adresse; + socklen_t taille = sizeof(adresse); + unsigned char message[BUFFER_SIZE]; + + int nboctets = recvfrom(s, message, BUFFER_SIZE, 0, (struct sockaddr *) padresse, &taille); + if(nboctets < 0) return -1; + + message[nboctets] = '\0'; + + traitement(message, nboctets); + } + return 0; +} + +void exemple_traitement(unsigned char *message, int length){ + (void) length; // on utilise pas length ici + + printf("Message recu :\n\n%s\n", message); +} + +int main(void){ + // init serveur + char service[50] = "2030"; + int socket = initialisationServeurUDP(service); + + // lancement boucle infinie + boucleServeurUDP(socket, exemple_traitement); + + return 0; +} \ No newline at end of file -- libgit2 0.21.2