ajout de tous les cours et TP préparés cet été

This commit is contained in:
2026-01-17 23:10:49 +01:00
parent ed9415bc81
commit 301cf5a98f
125 changed files with 21614 additions and 542 deletions

View File

@@ -106,7 +106,7 @@ Si vous n'êtes pas à l'aise avec le chiffre magique, une autre solution existe
- Changez tous les `1` en `0` et tous les `0` en `1` pour obtenir le masque de sous-réseau inversé.
3. **Effectuer une opération OU (OR) bit à bit** :
- Ajoutez chaque bit de l'adresse IP au bit correspondant du masque inversé.
- Cela revient à conserver les bits de l'adresse IP là où le masque inversé a des `0`, et à mettre des `1`ailleurs.
- Cela revient à conserver les bits de l'adresse IP là où le masque inversé a des `0`, et à mettre des `1` ailleurs.
4. **Convertir le résultat en décimal** :
- Le résultat de l'opération OU donne l'adresse de broadcast en binaire.
- Convertir cette adresse binaire en décimal pour obtenir l'adresse de broadcast.
@@ -131,3 +131,10 @@ Déterminez ladresse réseau et ladresse de broadcast des adresses suivant
2. `172.16.100.200/22`
3. `192.168.0.250/27`
---
Auteur : Florian Mathieu
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

245
Réseau/CORRIGE.md Normal file
View File

@@ -0,0 +1,245 @@
# Corrigé des exercices — Réseau
---
## Exercices du cours principal (README.md)
### Exercice d'application
**1. Trouvez votre adresse IP locale**
```sh
# Windows
ipconfig
# Linux/Mac
ifconfig
# ou
ip a
```
L'adresse IP locale apparaît généralement sous la forme `192.168.x.x` ou `10.x.x.x` dans la section de l'interface réseau active (Ethernet ou Wi-Fi).
**2. Testez une requête DNS**
```sh
nslookup www.example.com
```
Résultat typique :
```
Serveur : dns.google
Address: 8.8.8.8
Réponse ne faisant pas autorité :
Nom : www.example.com
Address: 93.184.216.34
```
**3. Comparez TCP et UDP**
| Usage | Protocole | Justification |
|-------|-----------|---------------|
| Envoyer un e-mail | **TCP** | Fiabilité nécessaire : tous les caractères doivent arriver dans l'ordre |
| Jouer en ligne | **UDP** | Rapidité prioritaire : une perte de paquet est acceptable (on perd une frame) |
| Regarder une vidéo en streaming | **UDP** | Rapidité prioritaire : un pixel perdu n'est pas critique |
---
## Exercices de calcul d'adresses IP (CALCUL.md)
### Exercice 1 : Application directe
#### 1. `10.0.5.150/20`
**Méthode magique :**
- Masque /20 = `255.255.240.0`
- Octet variable : 240 (3e octet)
- Incrément magique : 256 - 240 = **16**
- Valeur du 3e octet de l'IP : 5
- Multiple de 16 inférieur ou égal à 5 : **0**
**Résultats :**
- Adresse réseau : `10.0.0.0`
- Adresse de broadcast : `10.0.15.255` (0 + 16 - 1 = 15 pour le 3e octet, 255 pour le 4e)
**Vérification en binaire :**
- IP : `00001010.00000000.00000101.10010110`
- Masque : `11111111.11111111.11110000.00000000`
- AND : `00001010.00000000.00000000.00000000` = `10.0.0.0`
---
#### 2. `172.16.100.200/22`
**Méthode magique :**
- Masque /22 = `255.255.252.0`
- Octet variable : 252 (3e octet)
- Incrément magique : 256 - 252 = **4**
- Valeur du 3e octet de l'IP : 100
- Multiple de 4 inférieur ou égal à 100 : **100** (100 = 25 × 4)
**Résultats :**
- Adresse réseau : `172.16.100.0`
- Adresse de broadcast : `172.16.103.255` (100 + 4 - 1 = 103 pour le 3e octet)
**Vérification en binaire :**
- IP : `10101100.00010000.01100100.11001000`
- Masque : `11111111.11111111.11111100.00000000`
- AND : `10101100.00010000.01100100.00000000` = `172.16.100.0`
---
#### 3. `192.168.0.250/27`
**Méthode magique :**
- Masque /27 = `255.255.255.224`
- Octet variable : 224 (4e octet)
- Incrément magique : 256 - 224 = **32**
- Valeur du 4e octet de l'IP : 250
- Multiples de 32 : 0, 32, 64, 96, 128, 160, 192, **224**, 256
- Multiple de 32 inférieur ou égal à 250 : **224**
**Résultats :**
- Adresse réseau : `192.168.0.224`
- Adresse de broadcast : `192.168.0.255` (224 + 32 - 1 = 255)
**Vérification en binaire :**
- IP : `11000000.10101000.00000000.11111010`
- Masque : `11111111.11111111.11111111.11100000`
- AND : `11000000.10101000.00000000.11100000` = `192.168.0.224`
---
## Exercices TCP (tcp/README.md)
### Questions de réflexion
**1. Qu'est-ce que le routage des paquets engendre comme contrainte ?**
Le routage des paquets engendre plusieurs contraintes :
- **Latence** : Les paquets peuvent emprunter des chemins différents, certains plus longs que d'autres
- **Ordre d'arrivée** : Les paquets peuvent arriver dans le désordre (nécessite une numérotation)
- **Fiabilité** : Certains paquets peuvent se perdre en route (nécessite un accusé de réception)
- **Overhead** : Chaque paquet doit contenir des informations de routage (en-têtes)
**2. Pourquoi UDP est-il plus rapide que TCP ?**
UDP est plus rapide car :
- **Pas de connexion préalable** : TCP nécessite un "handshake" en 3 étapes (SYN, SYN-ACK, ACK)
- **Pas de numérotation** : Pas besoin d'ordonner les paquets
- **Pas d'accusé de réception** : Pas d'attente de confirmation
- **Pas de retransmission** : Si un paquet est perdu, on continue sans lui
- **En-têtes plus légers** : Moins de données de contrôle
**3. Services TCP vs UDP**
| Service | Protocole | Raison |
|---------|-----------|--------|
| Fichiers sur cloud | **TCP** | Intégrité des données critique |
| Streaming vidéo | **UDP** | Fluidité prioritaire |
**4. Que faire si un paquet se perd ?**
- **TCP** : Le protocole détecte la perte (pas d'ACK reçu) et retransmet automatiquement
- **UDP** : Le paquet est perdu définitivement, l'application doit gérer (ou ignorer)
**5. Que faire si un paquet arrive en double ?**
- **TCP** : Grâce à la numérotation, le doublon est détecté et ignoré
- **UDP** : L'application reçoit les deux copies
---
## Exercices DNS (dns/README.md)
### Questions sur les URL
**1. De combien de parties est composée une URL ?**
Une URL est composée de **5 parties** :
1. Protocole
2. Sous-domaine
3. Domaine principal
4. Domaine de deuxième niveau (TLD)
5. Répertoire (chemin)
**2. Définitions personnelles**
| Partie | Définition |
|--------|------------|
| Protocole | Règle de communication utilisée (HTTP, HTTPS, FTP...) |
| Sous-domaine | Subdivision du domaine principal (www, fr, blog...) |
| Domaine principal | Nom identifiant le site (google, wikipedia...) |
| TLD | Extension indiquant le type ou pays (.fr, .com, .org...) |
| Répertoire | Chemin vers la ressource demandée sur le serveur |
**3. Si une partie de l'URL est incorrecte ?**
- **Protocole incorrect** : Erreur de connexion ou redirection
- **Sous-domaine incorrect** : Erreur 404 ou DNS non résolu
- **Domaine incorrect** : DNS non résolu (NXDOMAIN)
- **TLD incorrect** : Site différent ou inexistant
- **Répertoire incorrect** : Erreur 404 (page non trouvée)
### Analyse de l'URL Wikipedia
URL : `https://fr.wikipedia.org/wiki/Ada_Lovelace`
| Partie | Type | Valeur |
|--------|------|--------|
| https | Protocole | Communication sécurisée |
| fr | Sous-domaine | Version française |
| wikipedia | Domaine Principal | Nom du site |
| org | Domaine de deuxième niveau | Organisation à but non lucratif |
| wiki/Ada_Lovelace | Répertoire | Article sur Ada Lovelace |
### Analyse de l'URL du lycée
URL : `https://www.lyc-thierry-maulnier.ac-nice.fr`
**Informations visibles :**
- Site sécurisé (HTTPS)
- Site web classique (www)
- Lycée Thierry Maulnier
- Académie de Nice
- Domaine français (.fr)
**Décomposition :**
| Partie | Valeur |
|--------|--------|
| Protocole | https |
| Sous-domaine | www |
| Domaine | lyc-thierry-maulnier |
| Sous-domaine académique | ac-nice |
| TLD | fr |
### Manipulation nslookup
```sh
nslookup www.google.fr
```
**Résultat typique :**
```
Nom : www.google.fr
Addresses: 142.250.179.99
2a00:1450:4007:818::2003
```
**Principe de fonctionnement :**
- `nslookup` interroge un serveur DNS
- Le serveur DNS traduit le nom de domaine en adresse IP
- L'adresse IPv4 et/ou IPv6 est retournée
**Constat en utilisant l'IP directement :**
- Le site fonctionne avec l'adresse IP
- Cela prouve que le DNS n'est qu'un "annuaire" de traduction
- Les serveurs web peuvent gérer plusieurs domaines sur une même IP (virtual hosts)
---
Auteur : Florian Mathieu
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -0,0 +1,424 @@
"""
Corrigé du TP Mini-Chat en Python
"""
import socket
import threading
# =============================================================================
# PARTIE 1 : Découverte des sockets
# =============================================================================
def afficher_info_reseau():
"""Affiche les informations réseau de la machine."""
nom_machine = socket.gethostname()
adresse_ip = socket.gethostbyname(nom_machine)
print(f"Nom de la machine : {nom_machine}")
print(f"Adresse IP locale : {adresse_ip}")
def resoudre_dns(domaine):
"""
Résout un nom de domaine en adresse IP.
:param domaine: (str) Le nom de domaine à résoudre
:return: (str) L'adresse IP correspondante
"""
try:
adresse_ip = socket.gethostbyname(domaine)
return adresse_ip
except socket.gaierror:
return f"Erreur : impossible de résoudre {domaine}"
# =============================================================================
# PARTIE 2 : Serveur TCP simple
# =============================================================================
def creer_serveur_tcp(port):
"""
Crée un serveur TCP qui attend une connexion et affiche le message reçu.
:param port: (int) Le port d'écoute
"""
# Créer le socket TCP
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Permettre la réutilisation de l'adresse
serveur.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Lier à toutes les interfaces sur le port spécifié
serveur.bind(('', port))
# Écouter (max 1 connexion en attente)
serveur.listen(1)
print(f"Serveur en écoute sur le port {port}...")
# Accepter une connexion
connexion, adresse = serveur.accept()
print(f"Connexion acceptée de {adresse[0]}:{adresse[1]}")
# Recevoir le message
donnees = connexion.recv(1024)
message = donnees.decode('utf-8')
print(f"Message reçu : {message}")
# Fermer les connexions
connexion.close()
serveur.close()
def creer_client_tcp(adresse_serveur, port, message):
"""
Crée un client TCP qui envoie un message au serveur.
:param adresse_serveur: (str) L'adresse IP du serveur
:param port: (int) Le port du serveur
:param message: (str) Le message à envoyer
"""
# Créer le socket TCP
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Se connecter au serveur
client.connect((adresse_serveur, port))
print(f"Connecté à {adresse_serveur}:{port}")
# Envoyer le message
client.send(message.encode('utf-8'))
print(f"Message envoyé : {message}")
# Fermer la connexion
client.close()
# =============================================================================
# PARTIE 3 : Chat bidirectionnel
# =============================================================================
def serveur_chat(port):
"""
Serveur de chat interactif.
"""
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serveur.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serveur.bind(('', port))
serveur.listen(1)
print(f"Serveur de chat en attente sur le port {port}...")
connexion, adresse = serveur.accept()
print(f"Connexion de {adresse[0]}:{adresse[1]}")
print("Chat démarré ! (le client envoie 'quit' pour terminer)\n")
while True:
# Recevoir un message du client
donnees = connexion.recv(1024)
if not donnees:
break
message_client = donnees.decode('utf-8')
print(f"[Client] {message_client}")
# Vérifier si le client veut quitter
if message_client.lower() == "quit":
print("Le client a quitté.")
break
# Envoyer une réponse
reponse = input("[Serveur] Votre réponse : ")
connexion.send(reponse.encode('utf-8'))
connexion.close()
serveur.close()
def client_chat(adresse_serveur, port):
"""
Client de chat interactif.
"""
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((adresse_serveur, port))
print(f"Connecté au serveur {adresse_serveur}:{port}")
print("Tapez 'quit' pour quitter.\n")
while True:
# Envoyer un message
message = input("[Vous] ")
client.send(message.encode('utf-8'))
# Quitter si demandé
if message.lower() == "quit":
print("Déconnexion...")
break
# Recevoir la réponse du serveur
reponse = client.recv(1024).decode('utf-8')
print(f"[Serveur] {reponse}")
client.close()
# =============================================================================
# PARTIE 4 : Comparaison TCP vs UDP
# =============================================================================
def serveur_udp(port):
"""
Serveur UDP simple.
"""
serveur = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # DGRAM = UDP
serveur.bind(('', port))
print(f"Serveur UDP en écoute sur le port {port}...")
while True:
# recvfrom retourne les données ET l'adresse de l'expéditeur
donnees, adresse = serveur.recvfrom(1024)
message = donnees.decode('utf-8')
print(f"[{adresse[0]}:{adresse[1]}] {message}")
if message.lower() == "quit":
break
serveur.close()
print("Serveur UDP arrêté.")
def client_udp(adresse_serveur, port):
"""
Client UDP simple.
"""
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print(f"Client UDP prêt à envoyer vers {adresse_serveur}:{port}")
print("Tapez 'quit' pour quitter.\n")
while True:
message = input("Message : ")
# sendto envoie directement sans connexion préalable
client.sendto(message.encode('utf-8'), (adresse_serveur, port))
if message.lower() == "quit":
break
client.close()
print("Client UDP arrêté.")
# =============================================================================
# PARTIE 5 : Mini-serveur multi-clients (Bonus)
# =============================================================================
clients = []
clients_lock = threading.Lock()
def gerer_client(connexion, adresse):
"""Gère la communication avec un client."""
print(f"[+] Nouveau client : {adresse}")
with clients_lock:
clients.append(connexion)
# Envoyer un message de bienvenue
connexion.send("Bienvenue sur le chat ! Tapez 'quit' pour quitter.\n".encode('utf-8'))
while True:
try:
message = connexion.recv(1024).decode('utf-8')
if not message or message.lower() == "quit":
break
print(f"[{adresse[0]}:{adresse[1]}] {message}")
# Diffuser le message à tous les autres clients
with clients_lock:
for client in clients:
if client != connexion:
try:
client.send(f"[{adresse[0]}:{adresse[1]}] {message}".encode('utf-8'))
except:
pass
except:
break
with clients_lock:
if connexion in clients:
clients.remove(connexion)
connexion.close()
print(f"[-] Client déconnecté : {adresse}")
def serveur_multi_clients(port):
"""Serveur acceptant plusieurs clients."""
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serveur.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serveur.bind(('', port))
serveur.listen(5)
print(f"Serveur multi-clients sur le port {port}")
print("En attente de connexions... (Ctrl+C pour arrêter)\n")
try:
while True:
connexion, adresse = serveur.accept()
thread = threading.Thread(target=gerer_client, args=(connexion, adresse))
thread.daemon = True
thread.start()
except KeyboardInterrupt:
print("\nArrêt du serveur...")
finally:
serveur.close()
def client_multi(adresse_serveur, port, pseudo):
"""Client pour le serveur multi-clients avec réception asynchrone."""
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((adresse_serveur, port))
print(f"Connecté au serveur {adresse_serveur}:{port} en tant que {pseudo}")
def recevoir():
"""Thread de réception des messages."""
while True:
try:
message = client.recv(1024).decode('utf-8')
if message:
print(f"\r{message}\n[{pseudo}] ", end='')
except:
break
# Lancer le thread de réception
thread_reception = threading.Thread(target=recevoir)
thread_reception.daemon = True
thread_reception.start()
# Boucle d'envoi
while True:
message = input(f"[{pseudo}] ")
if message.lower() == "quit":
client.send("quit".encode('utf-8'))
break
client.send(f"{pseudo}: {message}".encode('utf-8'))
client.close()
# =============================================================================
# PARTIE 6 : Réponses aux questions de synthèse
# =============================================================================
"""
RÉPONSES AUX QUESTIONS DE SYNTHÈSE
1. Différence entre SOCK_STREAM (TCP) et SOCK_DGRAM (UDP) :
- SOCK_STREAM (TCP) : Communication orientée connexion, fiable, ordonnée.
Les données arrivent dans l'ordre, sans perte ni duplication.
- SOCK_DGRAM (UDP) : Communication sans connexion, non fiable.
Les datagrammes peuvent arriver dans le désordre, être perdus ou dupliqués.
2. Pourquoi bind() pour le serveur et connect() pour le client ?
- Le serveur utilise bind() pour s'attacher à une adresse/port spécifique
et attendre les connexions entrantes (il écoute).
- Le client utilise connect() pour initier activement une connexion
vers un serveur connu (il se connecte à quelque chose qui existe déjà).
3. Que se passe-t-il si deux programmes utilisent le même port ?
- Le second programme recevra une erreur "Address already in use".
- Un port ne peut être utilisé que par un seul processus à la fois
(sauf configuration spéciale comme SO_REUSEADDR).
4. Pourquoi 127.0.0.1 (localhost) pour les tests ?
- C'est l'adresse de loopback qui pointe vers la machine locale.
- Les paquets ne quittent jamais la machine, idéal pour les tests.
- Pas besoin de configuration réseau ni de pare-feu.
5. Quand préférer UDP à TCP pour un chat ?
- Pour un chat vocal/vidéo en temps réel : la latence est critique,
perdre quelques paquets est acceptable (on n'entend pas un mot).
- Pour un chat textuel : TCP est préférable car chaque caractère compte.
"""
# =============================================================================
# TABLEAU COMPARATIF TCP vs UDP
# =============================================================================
"""
| Critère | TCP | UDP |
|------------------------|--------------------------|-------------------------|
| Connexion préalable | Oui (connect/accept) | Non (envoi direct) |
| Fonction d'envoi | send() | sendto() |
| Garantie de livraison | Oui (retransmission) | Non |
| Ordre des messages | Garanti | Non garanti |
| Utilisation typique | Web, email, fichiers | Streaming, jeux, VoIP |
"""
# =============================================================================
# TESTS
# =============================================================================
if __name__ == "__main__":
import sys
print("=" * 60)
print("CORRIGÉ DU TP MINI-CHAT")
print("=" * 60)
print("\n--- Partie 1 : Découverte des sockets ---\n")
print("Test afficher_info_reseau():")
afficher_info_reseau()
print("\nTest resoudre_dns():")
print(f"www.google.fr -> {resoudre_dns('www.google.fr')}")
print(f"www.wikipedia.org -> {resoudre_dns('www.wikipedia.org')}")
print("\n" + "=" * 60)
print("Pour tester les parties 2 à 5, lancez le script avec un argument :")
print(" python Corrige_TP_MiniChat.py serveur_tcp")
print(" python Corrige_TP_MiniChat.py client_tcp")
print(" python Corrige_TP_MiniChat.py serveur_chat")
print(" python Corrige_TP_MiniChat.py client_chat")
print(" python Corrige_TP_MiniChat.py serveur_udp")
print(" python Corrige_TP_MiniChat.py client_udp")
print(" python Corrige_TP_MiniChat.py serveur_multi")
print(" python Corrige_TP_MiniChat.py client_multi <pseudo>")
print("=" * 60)
if len(sys.argv) > 1:
commande = sys.argv[1]
if commande == "serveur_tcp":
creer_serveur_tcp(12345)
elif commande == "client_tcp":
creer_client_tcp('127.0.0.1', 12345, "Bonjour serveur !")
elif commande == "serveur_chat":
serveur_chat(12345)
elif commande == "client_chat":
client_chat('127.0.0.1', 12345)
elif commande == "serveur_udp":
serveur_udp(12345)
elif commande == "client_udp":
client_udp('127.0.0.1', 12345)
elif commande == "serveur_multi":
serveur_multi_clients(12345)
elif commande == "client_multi":
pseudo = sys.argv[2] if len(sys.argv) > 2 else "Anonyme"
client_multi('127.0.0.1', 12345, pseudo)
else:
print(f"Commande inconnue : {commande}")

View File

@@ -18,7 +18,7 @@ Le modèle OSI (Open Systems Interconnection) est un modèle théorique en 7 cou
| 4 | Transport | Transport fiable des données (ex : TCP, UDP) : Divise le message en plusieurs segments, puis le reconstitue à l'arrivée |
| 3 | Réseau | Routage des paquets (ex : IP) : S'occupe du trajet des paquets, en s'assurant de la bonne destination. |
| 2 | Liaison | Adressage physique (ex : Ethernet, Wi-Fi, MAC) : Adresses physiques et réseau local |
| 1 | Physique | Transmission des bits (ex : câbles, ondes radio) : Transmets les bits de manière effective. |
| 1 | Physique | Transmission des bits (ex : câbles, ondes radio) : Transmet les bits de manière effective. |
@@ -41,7 +41,7 @@ Le modèle TCP/IP est une simplification du modèle OSI, plus proche de l'implé
Chaque machine d'un réseau a une adresse unique appelée **adresse IP**.
### 2.1 Adresses IPv4
### Adresses IPv4
Une adresse IPv4 est constituée de 4 nombres entre 0 et 255, séparés par des points (ex : `192.168.1.1`).
Les adresses IPv4 sont divisées en **adresses publiques** (utilisées sur Internet) et **adresses privées** (utilisées dans les réseaux locaux).
@@ -116,7 +116,7 @@ Les réseaux sont la base d'Internet et des systèmes informatiques modernes. Co
### 🔍 Exercice d'application
1. Trouvez votre adresse IP locale avec la commande :
```sh
ipconfig (Windows) ou ifconfig/ip a (Linux/Mac)
ipconfig (Windows) ou ifconfig / ip a (Linux/Mac)
```
2. Testez une requête DNS avec :
```sh

380
Réseau/TP_MiniChat.md Normal file
View File

@@ -0,0 +1,380 @@
# TP : Mini-Chat en Python
## Contexte
Vous êtes développeur chez une startup qui souhaite créer une alternative légère à Discord. Votre mission : implémenter un système de messagerie instantanée en utilisant les **sockets Python** pour comprendre concrètement le fonctionnement des protocoles TCP et UDP.
Ce TP vous permettra de manipuler les concepts vus en cours : adresses IP, ports, protocoles de transport, et modèle client-serveur.
---
## Objectifs
- Comprendre le fonctionnement des sockets réseau
- Implémenter une communication client-serveur en TCP
- Comparer TCP et UDP en pratique
- Manipuler les adresses IP et les ports
---
## Prérequis
```python
import socket
```
Le module `socket` est inclus dans Python, aucune installation nécessaire.
---
## Partie 1 : Découverte des sockets
### 1.1. Qu'est-ce qu'un socket ?
Un **socket** est un point de terminaison pour envoyer ou recevoir des données sur un réseau. C'est comme une prise électrique : vous branchez votre programme dessus pour communiquer.
Un socket est identifié par :
- Une **adresse IP** (quelle machine)
- Un **port** (quelle application sur cette machine)
### 1.2. Récupérer son adresse IP
Créer un programme qui affiche votre nom d'hôte et votre adresse IP locale.
```python
import socket
def afficher_info_reseau():
"""Affiche les informations réseau de la machine."""
# À compléter
pass
# Test
afficher_info_reseau()
```
**Fonctions utiles :**
- `socket.gethostname()` : retourne le nom de la machine
- `socket.gethostbyname(nom)` : retourne l'adresse IP associée au nom
**Sortie attendue :**
```
Nom de la machine : MonPC
Adresse IP locale : 192.168.1.42
```
### 1.3. Résolution DNS
Créer une fonction qui résout un nom de domaine en adresse IP (comme `nslookup`).
```python
def resoudre_dns(domaine):
"""
Résout un nom de domaine en adresse IP.
:param domaine: (str) Le nom de domaine à résoudre
:return: (str) L'adresse IP correspondante
"""
# À compléter
pass
# Tests
print(resoudre_dns("www.google.fr"))
print(resoudre_dns("www.wikipedia.org"))
```
---
## Partie 2 : Serveur TCP simple
### 2.1. Création du serveur
Un serveur TCP fonctionne en plusieurs étapes :
1. Créer un socket
2. Lier le socket à une adresse et un port (`bind`)
3. Écouter les connexions (`listen`)
4. Accepter une connexion (`accept`)
5. Recevoir/Envoyer des données
6. Fermer la connexion
```python
import socket
def creer_serveur_tcp(port):
"""
Crée un serveur TCP qui attend une connexion et affiche le message reçu.
:param port: (int) Le port d'écoute
"""
# Créer le socket TCP
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Permettre la réutilisation de l'adresse
serveur.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Lier à toutes les interfaces sur le port spécifié
serveur.bind(('', port))
# Écouter (max 1 connexion en attente)
serveur.listen(1)
print(f"Serveur en écoute sur le port {port}...")
# À compléter : accepter une connexion et recevoir un message
pass
# Lancer le serveur sur le port 12345
creer_serveur_tcp(12345)
```
**Fonctions à utiliser :**
- `connexion, adresse = serveur.accept()` : accepte une connexion
- `donnees = connexion.recv(1024)` : reçoit jusqu'à 1024 octets
- `donnees.decode('utf-8')` : convertit les octets en texte
- `connexion.close()` : ferme la connexion
### 2.2. Création du client
```python
import socket
def creer_client_tcp(adresse_serveur, port, message):
"""
Crée un client TCP qui envoie un message au serveur.
:param adresse_serveur: (str) L'adresse IP du serveur
:param port: (int) Le port du serveur
:param message: (str) Le message à envoyer
"""
# Créer le socket TCP
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# À compléter : se connecter et envoyer le message
pass
# Envoyer un message au serveur local
creer_client_tcp('127.0.0.1', 12345, "Bonjour serveur !")
```
**Fonctions à utiliser :**
- `client.connect((adresse, port))` : se connecte au serveur
- `client.send(message.encode('utf-8'))` : envoie le message
### 2.3. Test
1. Ouvrir deux terminaux
2. Dans le premier, lancer le serveur
3. Dans le second, lancer le client
4. Observer le message reçu par le serveur
---
## Partie 3 : Chat bidirectionnel
### 3.1. Serveur de chat
Modifier le serveur pour qu'il puisse :
- Recevoir un message du client
- Répondre au client
- Continuer la conversation jusqu'à ce que le client envoie "quit"
```python
def serveur_chat(port):
"""
Serveur de chat interactif.
"""
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serveur.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serveur.bind(('', port))
serveur.listen(1)
print(f"Serveur de chat en attente sur le port {port}...")
connexion, adresse = serveur.accept()
print(f"Connexion de {adresse[0]}:{adresse[1]}")
# À compléter : boucle de conversation
# - Recevoir un message
# - Si le message est "quit", terminer
# - Sinon, demander une réponse et l'envoyer
pass
```
### 3.2. Client de chat
```python
def client_chat(adresse_serveur, port):
"""
Client de chat interactif.
"""
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((adresse_serveur, port))
print(f"Connecté au serveur {adresse_serveur}:{port}")
print("Tapez 'quit' pour quitter.\n")
# À compléter : boucle de conversation
# - Demander un message à l'utilisateur
# - Envoyer le message
# - Si "quit", terminer
# - Sinon, attendre et afficher la réponse
pass
```
---
## Partie 4 : Comparaison TCP vs UDP
### 4.1. Serveur UDP
UDP est "connectionless" : pas besoin d'établir une connexion avant d'envoyer des données.
```python
def serveur_udp(port):
"""
Serveur UDP simple.
"""
serveur = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # DGRAM = UDP
serveur.bind(('', port))
print(f"Serveur UDP en écoute sur le port {port}...")
while True:
# recvfrom retourne les données ET l'adresse de l'expéditeur
donnees, adresse = serveur.recvfrom(1024)
message = donnees.decode('utf-8')
print(f"[{adresse[0]}:{adresse[1]}] {message}")
if message.lower() == "quit":
break
serveur.close()
```
### 4.2. Client UDP
```python
def client_udp(adresse_serveur, port):
"""
Client UDP simple.
"""
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
message = input("Message (quit pour quitter) : ")
# sendto envoie directement sans connexion préalable
client.sendto(message.encode('utf-8'), (adresse_serveur, port))
if message.lower() == "quit":
break
client.close()
```
### 4.3. Analyse comparative
Compléter le tableau suivant après avoir testé les deux versions :
| Critère | TCP | UDP |
|---------|-----|-----|
| Connexion préalable | ... | ... |
| Fonction d'envoi | ... | ... |
| Garantie de livraison | ... | ... |
| Ordre des messages | ... | ... |
| Utilisation typique | ... | ... |
---
## Partie 5 : Mini-serveur multi-clients (Bonus)
### 5.1. Problème
Le serveur actuel ne peut gérer qu'un seul client. Pour accepter plusieurs clients simultanément, il faut utiliser les **threads**.
```python
import socket
import threading
clients = []
def gerer_client(connexion, adresse):
"""Gère la communication avec un client."""
print(f"[+] Nouveau client : {adresse}")
clients.append(connexion)
while True:
try:
message = connexion.recv(1024).decode('utf-8')
if not message or message.lower() == "quit":
break
# Diffuser le message à tous les clients
for client in clients:
if client != connexion:
client.send(f"[{adresse[0]}] {message}".encode('utf-8'))
except:
break
clients.remove(connexion)
connexion.close()
print(f"[-] Client déconnecté : {adresse}")
def serveur_multi_clients(port):
"""Serveur acceptant plusieurs clients."""
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serveur.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serveur.bind(('', port))
serveur.listen(5)
print(f"Serveur multi-clients sur le port {port}")
while True:
connexion, adresse = serveur.accept()
thread = threading.Thread(target=gerer_client, args=(connexion, adresse))
thread.start()
```
### 5.2. Client amélioré
Créer un client qui peut recevoir des messages tout en permettant d'en envoyer (utiliser un thread pour la réception).
---
## Partie 6 : Questions de synthèse
1. **Expliquer** la différence entre `SOCK_STREAM` (TCP) et `SOCK_DGRAM` (UDP).
2. **Pourquoi** le serveur utilise-t-il `bind()` alors que le client utilise `connect()` ?
3. **Que se passe-t-il** si deux programmes essaient d'utiliser le même port simultanément ?
4. **Pourquoi** utilise-t-on `127.0.0.1` (localhost) pour les tests ?
5. **Dans quel cas** préféreriez-vous UDP à TCP pour une application de chat ?
---
## Barème indicatif
| Partie | Points |
|--------|--------|
| Partie 1 : Découverte | 3 |
| Partie 2 : Serveur/Client TCP | 5 |
| Partie 3 : Chat bidirectionnel | 4 |
| Partie 4 : Comparaison TCP/UDP | 4 |
| Partie 5 : Multi-clients (Bonus) | 2 |
| Partie 6 : Questions | 2 |
| **Total** | **20** |
---
Auteur : Florian Mathieu
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -7,7 +7,7 @@
> Et que dire de Bob, qui fait f5 toutes les 10 min sur 46.33.191.5 ?
Cela vous parait idiot ? Pourtant les adresses IP citées au dessus sont bel et bien utilisées quotidiennement par des milliers de personnes. Néanmoins, vous les connaissez probablement mieux sous leur petit nom *__google__*, *__tiktok__* et *__pronote__* !
Cela vous paraît idiot ? Pourtant les adresses IP citées au-dessus sont bel et bien utilisées quotidiennement par des milliers de personnes. Néanmoins, vous les connaissez probablement mieux sous leur petit nom *__google__*, *__tiktok__* et *__pronote__* !
Comme nous l'avons vu avec l'adresse IP, chaque machine possède un identifiant sur le réseau. Tout comme chaque personne possède une adresse physique : lorsque vous allez voir tatie Monique, vous vous rendez là où elle vit, et bien c'est pareil avec un site internet.
@@ -20,9 +20,9 @@ Si, à l'époque, on stockait les adresses des sites dans un fichier HOST.TXT, c
Très rapidement, cette solution devint ingérable au vu de la croissance exponentielle du nombre de sites mis en ligne.
En 1983, le DNS voit le jour. Et très rapidement, ce système montra son utilité : quatre années plus tard, on enregistrait plus de 20 000 enregistrements de nom de domaine.
Pour nous autres, êtres humains, il est complexe de retenir toutes les adresses IP des sites que l'on souhaite visiter. Et à moins de tout noter dans un repertoire, jamais vous ne vous rappelerez de tous ces nombres.
Pour nous autres, êtres humains, il est complexe de retenir toutes les adresses IP des sites que l'on souhaite visiter. Et à moins de tout noter dans un répertoire, jamais vous ne vous rappellerez de tous ces nombres.
C'est pour cela que le __protocole__ *Domain Name System* a été crée.
C'est pour cela que le __protocole__ *Domain Name System* a été créé.
![dns.gif](assets/dns.gif)
@@ -49,7 +49,7 @@ Toutes ces adresses vont être enregistrées auprès d'un organisme, *L'ICANN*.
> Vous l'aurez compris, le principe du DNS est de faire le lien entre l'adresse IP et l'URL d'un site.
Mais c'est quoi, une URL ?
Une URL, ou Uniform Ressource Locator, est composée de 5 parties; le protocole, le sous-domaine, le nom de domaine principal, le domaine de deuxième niveau et le répertoire.
Une URL, ou Uniform Resource Locator, est composée de 5 parties : le protocole, le sous-domaine, le nom de domaine principal, le domaine de deuxième niveau et le répertoire.
Par exemple, dans cette adresse, que peut on retrouver ?
@@ -70,7 +70,7 @@ Répondez aux questions suivantes :
- De combien de parties est composée une url ?
- Pour chaque partie, donner votre propre définition
- Si une partie de l'URL est incorrecte, que se passe -il ?
- Si une partie de l'URL est incorrecte, que se passe-t-il ?
Voici une autre url : https://fr.wikipedia.org/wiki/Ada_Lovelace
@@ -115,9 +115,9 @@ subgraph Sous-domaines de wikipedia
--------
### Resolution de nom
### Résolution de nom
Que se passe t-il lorsque l'on tape dans son navigateur web *__ViveLaSNT.fr__* ?
Que se passe-t-il lorsque l'on tape dans son navigateur web *__ViveLaSNT.fr__* ?
[![Resolution de nom](https://img.youtube.com/vi/av0zX-dr8o8/0.jpg)](https://www.youtube.com/watch?v=av0zX-dr8o8)

View File

@@ -14,7 +14,7 @@ Dans le merveilleux monde d'Internet, c'est la même chose, grâce à l'adresse
Arobase souhaite passer une commande auprès d'une célèbre chaine de magasin de meuble. Hélas, le paquet est trop gros pour être livré en une fois, en effet, le poids maximum d'un colis est de 1,5 kg.
*Quelle solution le commerçant va t-il choisir pour expédier les différents colis ?*
*Quelle solution le commerçant va-t-il choisir pour expédier les différents colis ?*
*__Problématiques__* :
@@ -23,17 +23,17 @@ Arobase souhaite passer une commande auprès d'une célèbre chaine de magasin d
__En informatique__
Cela fonctionne de la même manière : Arobase souhaite envoyer télécharger un gros fichier depuis un serveur https. Les problèmatiques restent les mêmes :
Cela fonctionne de la même manière : Arobase souhaite télécharger un gros fichier depuis un serveur HTTPS. Les problématiques restent les mêmes :
- Comment découper le fichier ?
- Comment s'assurer que tous les "morceaux" de fichiers parviennent à destination ?
## Deux méthodes d'envoie
## Deux méthodes d'envoi
Arobase a le choix entre deux méthodes de livraison :
- Soit l'ensemble des paquets sera livrée en trois jours, avec une numérotation précise de chaque colis
- Soit l'ensemble des paquets sera livré en trois jours, avec une numérotation précise de chaque colis
- Soit la commande arrivera dès le lendemain, mais sans aucune garantie de fiabilité
On peut rapprocher ces deux méthodes à deux protocoles de transmission de données :
@@ -43,7 +43,7 @@ On peut rapprocher ces deux méthodes à deux protocoles de transmission de donn
### TCP
TCP assure une qualité de service, c'est à dire qu'il assure le découpage du fichier en plus petits paquets, en permettant le routage des données par quelques chemins que cela soit tout en promettant une reconstitution des fichiers demandés dans le bon ordre, grâce à une numérotation précise des données.
TCP assure une qualité de service, c'est-à-dire qu'il assure le découpage du fichier en plus petits paquets, en permettant le routage des données quels que soient les chemins empruntés, tout en promettant une reconstitution des fichiers demandés dans le bon ordre, grâce à une numérotation précise des données.
*__Selon vous, qu'est ce que le routage des paquets (c'est à dire le fait de pouvoir disperser les données à travers Internet tout en s'assurant qu'elles parviennent à destination) engendre comme contrainte ?__*
@@ -62,7 +62,7 @@ On suppose qu'Arobase souhaite envoyer des fichiers personnels sur son cloud Bob
- Que faire si un paquet se perd ?
- Que faire si un paquet arrive en double ?
## Mais au fait, comment se font ces échanges tcp ?
## Mais au fait, comment se font ces échanges TCP ?
Voilà comment se déroule un échange entre un client et un serveur TCP.
@@ -78,7 +78,7 @@ Hélas on voit ici que le message était trop long, et que le canal s'est referm
![blague_1.png](assets/blague_3.png)
Et que se passe t-il dans ce cas ...?
Et que se passe-t-il dans ce cas... ?
![blague_4.png](assets/blague_4.png)