Plusieurs organismes interviennent à différents niveaux
N | Unité | Nom | Utilisation |
---|---|---|---|
7 | — | Application | Logiciel |
6 | — | Presentation | Chiffrement |
5 | — | Session | Connexion, identification |
4 | Segment | Transport | Intégrité des données |
3 | Paquet | Network | Acheminement (routage) |
2 | Trame | Data-link | Encodage sur le support physique |
1 | Bit | Physical | Matériel (voltage, nature des câbles, …) |
Chaque couche règle de manière transparente pour les
couches supérieures un problème spécifique. Une couche de
niveau N n'a aucun contrôle sur une couche de niveau
inférieur.
Ce modèle constitue la norme ISO/IEC 7498-1.
(ISO 7497 le engrais, ISO 7495 concerne les farines de blé
tendre, ISO 7490 les implants dentaires, …).
Modèle en 4 couches, similaire au modèle OSI :
N | Nom | Description | Eq. OSI |
---|---|---|---|
4 | Application | HTTP, Bitorrent, FTP, … | 5, 6, 7 |
3 | Transport | TCP, UDP, SCTP, … | 4 |
2 | Internet | IP (v4, v6), ICMP, IPsec, … | 3 |
1 | Link | Ethernet, 802.11, … | 1, 2 |
Nous allons montrer comment le réseau global Internet est construit et donner des exemples de protocoles dans chaque couche.
En première approximation, les protocoles de la couche de liaison sont spécifiques à un matériel particulier :
Un protocole de la couche de liaison ne permet de connecter que des machines connectées au même type de support.
Cette couche permet de connecter entre eux des réseaux physiques
différents.
Le protocole utilisé est majoritairement IP (Internet Protocol) :
139.17.8.47 139.17.8.1 200.100.99.27 89.22.39.126 10.0.34.8 10.0.34.12 10.0.34.14
Qui décide des adresses IP ?
Comment déterminer le chemin à prendre ?
Une machine A veut envoyer un message à une machine D. Les deux machines ne sont pas directement reliées (pas de câble point-à-point, pas sur le même switch, pas sur le même réseau Wifi, …)
Exemple :
$ route
Kernel IP routing table
Destination Gateway Genmask ... Iface
192.168.0.0 * 255.255.255.0 ... eth1
129.175.240.0 * 255.255.255.0 ... eth0
default 129.175.240.1 0.0.0.0 ... eth0
Transmission d'un paquet d'une machine A1 à une machine C3
Combien de machines peut on adresser avec IPv4 ?
256 × 256 × 256 × 256 = 232 = 4 294 967 296
Insuffisance du nombre d'adresses liée aux facteurs suivants :
On utilise un masque i.e. un nombre dont le « et » binaire avec l'adresse va isoler la partie réseau.
décimal | 129 | 175 | 34 | 35 |
binaire | 10000001 | 10101111 | 00100010 | 00100011 |
masque | 11111111 | 11111111 | 11110000 | 00000000 |
« ET » | 10000001 | 10101111 | 00100000 | 00000000 |
sous-réseau | 129 | 175 | 32 | 0 |
masque inversé | 00000000 | 00000000 | 00001111 | 11111111 |
« ET » | 00000000 | 00000000 | 00000010 | 00100011 |
machine | 0 | 0 | 2 | 35 |
Le standard réserve 3 blocs d'adresses :
Ces adresses ne peuvent jamais être données à une machine sur Internet. Elles sont utilisées par le réseau local. Seul le routeur possède une adresse publique et il s'occupe de faire la traduction entre adresses locales et adresses globales (NAT : Network Address Translation)
On veut envoyer de l'information entre une machine A et une machine B (une image, une vidéo, …).
Qu'est-ce qu'il nous manque ?
Autre problème : on peut avoir plusieurs applications réseaux sur la même machine (i.e. à la même adresse IP). Par exemple:
On ne veut pas que les données à destination des différentes applications soient mélangées.
C'est le rôle de la couche de transport.
Le Transmission Control Protocol est un protocole au dessus d'IP qui permet de garantir l'intégrité des données.
Quand on veut envoyer une information d'une machine à une autre :
(c'est une explication simplifiée)
Lors du découpage d'une donnée en morceaux, TCP numérote les morceaux.
La couche TCP définit une notion de port. Un port est un identifiant numérique associé à une connexion TCP. Un service (ou serveur) est identifié de manière unique par son adresse IP et son numéro de port. Par convention, certains ports sont réservés pour des services particuliers :
L'utilité d'un port est de pouvoir faire « tourner » plusieurs services sur la même machine (même IP).
On a un moyen générique et fiable d'envoyer des données de taille arbitraire entre deux machines. Une fois ce mécanisme en place, c'est le programme utilisateur qui décide de la forme des données à envoyer : c'est la couche d'application.
Exemple le protocole HTTP sur lequel on reviendra :
GET /page.html HTTP/1.1
Host: www.toto.com:80
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0
...
Une application de messagerie n'enverra pas le même type de messages, et utilisera probablement un numéro de port différent.
Domain Name System : permet d'attribuer un nom à une IP (annuaire). Double avantage :
Principe hiérarchise :
La programmation d'applications réseau se fait en général au niveau TCP.
On veut envoyer des données, c'est à dire des suites d'octets sur le réseau.
En Python, on ne peut pas utiliser des chaînes de caractères, à
cause de l'encodage UTF-8.
Supposons qu'on veuille envoyer les octets : 0x8b 0x8b = 139
139.
C'est une séquence UTF-8 invalide. Pourtant on pourrait légitimement
envoyer ces octets (par exemple, parce qu'on envoie une image ou un fichier
binaire, …).
Solution : Python propose un type prédéfini de chaînes d'octets.
>>> b'ABCDE\x8b\x8b'
b'ABCDE\x8b\x8b'
>>> b'ABCDE\x8b\x8b' + b'toto'
b'ABCDE\x8b\x8btoto'
>>> len(b'ABCDE\x8b\x8b')
7
Les chaînes d'octets sont préfixées par b
On peut convertir une chaîne de caractères en chaîne d'octets avec l'opération .encode(). Par défaut cette opération utilise l'encodage UTF-8.
>>> 'ABCD'.encode()
b'ABCDE'
>>> b'ABCDÉ'.encode()
b'ABCD\xc3\x89'
>>> '🐵'.encode()
b'\xf0\x9f\x90\xb5'
Les chaînes d'octets possèdent l'opération inverse .decode()
>>> b'ABCD'.decode()
'ABCDE'
>>> b'\xf0\x9f\x90\xb5'.decode()
'🐵'
>>> b'\x8b\x8b'.decode()
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 0: invalid start byte
Attention, toutes les chaînes d'octets ne sont pas convertible en chaînes de caractères.
Le module socket possède un grand nombre de fonctions utilitaires :
La fonction gethostbyname(s) renvoie l'adresse IP de la machine dont on donne le nom.
>>> from socket import gethostbyname
>>> gethostbyname('www.universite-paris-saclay.fr')
'129.175.212.146'
>>> gethostbyname('www.google.fr')
'216.58.204.99'
>>> gethostnyname('www.existepas.it')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
socket.gaierror: [Errno -2] Name or service not known
Attention, il s'agit d'une fonction socket qui est dans le module dmuême nom !
Cette fonction permet de créer une connexion réseau, par défaut en TCP.
>>> from socket import socket
>>> cnx = socket()
Une fois la connexion crée il faut choisir : soit on est un serveur, soit on est un client. On peut ensuite envoyer et recevoir des données.
Une fois connecté, on peut utiliser les opérations cnx.send(msg) pour envoyer la chaîne d'octets msg à notre destinataire.
On peut aussi utiliser cnx.recv(n) pour lire un message de au plus n octets. Si on reçoit une chaîne vide, la connexion est terminée.
Attention, si on envoie et que personne ne lit, on peut saturer la
connexion.
De même si on attent des octets mais que personne n'écrit, on est bloqué.
C'est un serveur basique qui attend des connexions sur un port (on choisit 9191) et qui affiche dans la console tout ce qu'il reçoit, sans répondre.
Pour mettre une connexion en mode « serveur » on utilise l'opération cnx.bind(a) où a est une paire formée de l'adressse spéciale '0.0.0.0' edtu numéro de port. On peut ensuite appeler l'opération cnx.listen().
Une fois la socket en mode serveur, on peut utiliser l'opération .accept(). Cette opération bloque le calcul et attend une connexion. Lors de la connexion, l'opération renvoie une paire : (sclient, aclient) formée d'une connexion vers le client spécifique qui vient de ce connecter (sclient) et aclient la paire de son adresse IP et du port sur lequel il parle.
Dans un fichier serveur_echo.py
from socket import socket
addr = ('0.0.0.0', 9191) #adresse et port
cnx = socket()
cnx.bind(addr) #on devient un serveur
while True: #pour toujours…
sclient, aclient = cnx.listen() #on attend un client
#ici le client est connecté
msg = sclient.recv(1024) #on lit au plus 1000 octets
while len (msg) != 0: #tant que le client nous écrit
print(">>>", msg) #on affiche dans la console
msg = sclient.recv(1024) #on lit la suite
#fin du while interne, on se remet à écouter.
On va écrire un simple client, qui envoie le message HELLO puis se déconnecte
Dans un fichier client_hello.py
from socket import socket
addr = ('127.0.0.1', 9191)
cnx = socket()
cnx.connect(addr) #on se connecte au serveur
msg = b"HELLO"
n = cnx.send(msg) #on envoie le message
if n != len(msg):
print ("Le serveur n'a pas tout lu !")
cnx.close() #on termine
On a fait un bref survol des réseaux, c'est plutot un cours « pour la culture »
Beaucoup de détails ont été masqués. Il y a des cours de Réseaux et Réseaux avancés en L2 et L3, et un parcours de Master orienté Réseaux
Les points pricipaux
On se servira des TPs pour découvrir quelques petites commandes réseaux et faire du code très simple en Python.