PROGRAMMATION RÉSEAU EN PYTHON - EMMANUEL FLEURY - LABRI
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
Programmation Réseau en Python Emmanuel Fleury David Renault LaBRI, Université de Bordeaux, France 8 janvier 2020 E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 1 / 30
Agenda 1 L’Internet 2 Les Protocoles Réseau 3 Le Protocole HTTP E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 2 / 30
Overview 1 L’Internet 2 Les Protocoles Réseau 3 Le Protocole HTTP E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 3 / 30
Petite Histoire d’Internet 1960 : J.C.R. Licklider pose les premiers concepts d’Internet. 1962 : Début du programme ARPANET mené par la DARPA ; 1969 : L’Internet connecte quatre Universités américaines ; (MIT, UCLA, UCSB et l’Université d’Utah) 1971 : Envoi du premier e-mail par Ray Tomlinsen ; 1973 : Vinton Cerf et Robert Kahn posent les bases de TCP/IP ; 1985 : Premier nom de domaine enregistré ; 1989 : Invention du Web par Tim Berners-Lee au CERN (Genève) ; 1991 : Premier site Web mis en ligne par Tim Berners-Lee ; 1994 : Création de Yahoo (David Filo, Jerry Yang) et d’Amazon (Jeff Bezos) ; 1998 : Création de Google (Sergey Brin, Larry Page) ; 2001 : Création de Wikipédia (Larry Sanger, Jimmy Wales) ; 2004 : Création de Facebook (Mark Zuckerberg) ; 2006 : Création de Twitter (Jack Dorsey) ; 2010 : Création d’Instagram (Mike Krieger, Kevin Systrom) ; ... E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 4 / 30
L’Internet Définition (simplifiée) L’Internet est constitué par l’interconnexion de réseaux informatiques et de divers réseaux de télécommunication (câbles, satellites, . . .). Attention ! L’Internet n’est pas restreint seulement au Web ! Il existe plein d’autres protocoles (FTP, SSH, ICMP, . . .) ; L’Internet n’est pas gratuit ! Il faut créer et maintenir l’infra-structure réseau (FAI) ; L’Internet n’est pas naturellement neutre et libre ! Certains pays (la plupart en fait) décident de filtrer l’Internet à des degrés plus ou moins importants selon le régime politique qui y est pratiqué. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 5 / 30
Neutralité du Net Neutralité du Net Principe garantissant l’égalité de traitement de tous les flux de données sur Internet sans distinction ; Cela exclut toute discrimination positive ou négative à l’égard de la source, de la destination ou du contenu de l’information transmise sur le réseau. Les craintes Les FAI feront payer en fonction du service offert (par pays accessibles, par exemple) ; Les FAI pourront interdire ou rendre difficile l’accès à certains services en ligne (Netflix, Téléchargements, . . .) ; Un accès non-équitable aux réseaux crée une discrimination (pour les utilisateurs et pour les fournisseurs de services). E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 6 / 30
Adresses Internet (pour les machines) Une adresse Internet est l’identifiant d’une carte réseau IP (Internet Protocole) version 6 ; IP (Internet Protocole) version 4 ; Les adresses des interfaces réseau sont Les adresses des interfaces réseau sont codées sur 8 entiers de 16-bits (de 0x0 à codées sur 4 entiers de 8-bits (de 0 à 255) 0xffff) représentés sous forme représentés sous forme décimale et hexadécimale et séparées par deux points séparées par un point (’.’) ; (’:’) ; L’adresse totale est un entier de 32-bits L’adresse totale est un entier de 128-bits (4.109 adresses possibles) ; (3.1038 adresses possibles) ; L’adresse de la machine elle-même L’adresse de la machine elle-même (loopback) est ’127.0.0.1’ par (loopback) est ’::1’ par convention. convention. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 7 / 30
Noms de Domaines (pour les humains) Problème : Difficile de se rappeler des adresses IP (les nombres c’est pour les machines). Solution : On donne des noms “human-friendly” aux serveurs (Noms de Domaines) pour s’y connecter et on demandera aux machines de faire la traduction. Un nom de domaine est l’identifiant lisible d’une carte réseau Format : Exemples de noms de domaines : ’google.com’, ’wikipedia.org’, ’impots.gouv.fr’, . . . Exemples de Top Level Domain : Par activités : com, edu, org, gov, . . . Par pays : be, fr, uk, au, . . . E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 8 / 30
Domain Name System (DNS) Ce sont les machines qui vont traduire le nom de domaine en adresse IP Example : Demandons de résoudre l’URL ’www.anouar.im’. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 9 / 30
Pratiquons un peu ! Programmons un résolveur de nom de domaine avec le module socket de Python : import socket domain_name = input("Donnez un nom de domaine: ") ipv4_addr = socket.gethostbyname(domain_name) print("L'adresse IPv4 de '{}' est {}".format(domain_name, ipv4_addr)) Donnez un nom de domaine: google.com L'adresse IPv4 de 'google.com' est 172.217.171.238 1 Écrivez le programme ci-dessus et essayez le avec quelques noms de domaines. 2 Mais, notre résolveur DNS ne donne que l’adresse IPv4, il faudrait qu’il donne aussi l’IPv6. Utilisez les méthodes suivantes pour récupérer les adresses IPs correspondantes : ipv4_addr = socket.getaddrinfo(domain_name, None, socket.AF_INET) ipv6_addr = socket.getaddrinfo(domain_name, None, socket.AF_INET6) Affichez les et n’oubliez pas de filtrer le tuple de retour pour ne garder que l’addresse IP. 3 (Avancé) En utilisant ’try...except’, couvrez le cas où le nom de domaine n’existe pas ou encore, qu’il ne possède qu’un type d’IP. Par exemple : Donnez un nom de domaine: toto.net Donnez un nom de domaine: aaaaaaa L'adresse IPv4 de 'toto.net' est 162.215.249.14 Le domaine aaaaaaa n'a pas d'adresse ipv4! Le domaine toto.net n'a pas d'adresse ipv6! Le domaine aaaaaaa n'a pas d'adresse ipv6! E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 10 / 30
Résolveur de nom de domaine (corrigé) import socket # Get domain name from user domain_name = input("Donnez un nom de domaine: ") # Resolve IPv4 domain name ipv4_2_addr = socket.getaddrinfo(domain_name, None, socket.AF_INET)[0][4][0] print("L'adresse IPv4 de '{}' est {}".format(domain_name, ipv4_2_addr)) # Resolve IPv6 domain name ipv6_addr = socket.getaddrinfo(domain_name, None, socket.AF_INET6)[0][4][0] print("L'adresse IPv6 de '{}' est {}".format(domain_name, ipv6_addr)) E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 11 / 30
Résolveur de nom de domaine (corrigé) import socket # Get domain name from user domain_name = input("Donnez un nom de domaine: ") # Resolve IPv4 domain name try: ipv4_2_addr = socket.getaddrinfo(domain_name, None, socket.AF_INET)[0][4][0] print("L'adresse IPv4 de '{}' est {}".format(domain_name, ipv4_2_addr)) except: print("Le domaine {} n'a pas d'adresse ipv4!".format(domain_name)) # Resolve IPv6 domain name try: ipv6_addr = socket.getaddrinfo(domain_name, None, socket.AF_INET6)[0][4][0] print("L'adresse IPv6 de '{}' est {}".format(domain_name, ipv6_addr)) except: print("Le domaine {} n'a pas d'adresse ipv6!".format(domain_name)) E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 12 / 30
Overview 1 L’Internet 2 Les Protocoles Réseau 3 Le Protocole HTTP E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 13 / 30
C’est quoi un protocole ? Protocole Réseau Un ensemble de règles permettant à un ensemble d’entités de se coordonner à travers le réseau pour accomplir une tâche (souvent le transfert d’information). Mais, les entités peuvent jouer des rôles différents selon les tâches à effectuer. Exemple : architecture Client/Serveur Client : Machine ou application qui réclame un service à un serveur. Serveur : Machine ou application qui propose un certain nombre de services à des clients via le réseau. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 14 / 30
Modèle (simplifié) du protocole réseau Les protocoles se partagent les tâches selon un système en couches. Couche Applicative Gère les protocoles qui sont directement utilisés par les applications de l’utilisateur final ; Couche Transport Gère le transfert des données brutes sur le réseau (TCP ou UDP) ; Couche Réseau Gère l’acheminement des données jusqu’à la destination (routage) ; Couche Physique (ou Lien) Gère le transit des données sur le support physique (ondes radio, câble conducteur, . . .). E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 15 / 30
Quelques autres protocoles FTP (File Transfer Protocol, port 21) : Sert à télécharger des fichiers stockés sur un serveur distant ; SSH (Secure Shell, port 22) : Sert à se connecter de manière sécurisée sur d’autres machines ; SMTP (Simple Mail Transfer Protocol, port 25) : Sert à envoyer des e-mails ; IMAP (Internet Message Access Protocol, port 143) : Sert à télécharger ses e-mails pour les consulter ; ... E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 16 / 30
Sockets réseau Une seule machine peut vouloir gérer plusieurs tâches réseau simultanément. Une socket est un couple constitué d’une carte réseau et d’un port. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 17 / 30
Pratiquons un peu ! (1/3) Programmons un serveur qui retourne tout ce qu’a dit le client à l’identique. Le serveur import socket HOST = '127.0.0.1' # Fait reference a la machine locale (localhost) PORT = 1337 # Le port sur lequel on va attendre le client # Creation du socket encore non initialise sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((HOST, PORT)) # Initialise the socket à (HOST, PORT) sock.listen() # Ecoute le socket en l'attente du client conn, addr = sock.accept() # Si le client arrive, on cree la connexion print("Connexion établie avec {}".format(addr[0])) ######################################### #### Le code du serveur vient ici! #### ######################################### conn.close() # Ferme la connexion avec le client sock.close() # Ferme le socket sur l'ordinateur E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 18 / 30
Pratiquons un peu ! (2/3) Programmons un serveur qui retourne tout ce qu’a dit le client à l’identique. Le client import socket HOST = '127.0.0.1' # Fait reference à la machine locale (localhost) PORT = 1337 # Le port sur lequel on va attendre le client # Creation du socket encore non initialise sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) # Ouvre une connexion vers le serveur ######################################## #### Le code du client vient ici! #### ######################################## sock.close() # Ferme le socket sur l'ordinateur E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 19 / 30
Pratiquons un peu ! (3/3) 1 Vérifiez que la connexion s’établit en exécutant le serveur et le client sur votre machine. 2 Un code simplifié du serveur, une fois le client connecté à lui serait : data = conn.recv(1024) # Attend un envoi de la part du client print("Client: " + data.decode()) # Imprime ce que lui a envoye le client conn.sendall(data) # Renvoie le message au client Vérifiez que le serveur est bien en attente du message du client en exécutant ce code. Notez que l’envoi d’une chaîne de caractères Python sur le réseau, requiert de l’encoder et de la décoder si on la reçoit ! Cela vient du fait que les chaînes de caractères en Python contiennent plus que seulement les simples caractères (ce sont des objets) et on ne peut envoyer que les simples caractères sur le réseau. 3 Un code simplifié du client, une fois qu’il est connecté serait : msg = input("Message pour le serveur: ") # Recupere le message à envoyer sock.sendall(msg.encode()) # Envoie le message au serveur data = sock.recv(1024) # Recoit une reponse du serveur print("Serveur: {}".format(data.decode())) # Affiche la reponse du serveur Vérifiez que le client envoie son message au serveur et que le serveur le reçoit correctement. 4 (Avancé) Le problème de ce protocole est qu’il n’envoie qu’un seul et unique message. Essayez de le transformer pour qu’il permette d’en envoyer autant que l’on veut et que le client termine si le message est ’quitter’. On utilisera une boucle ’while True:’. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 20 / 30
Client/Serveur (corrigé) Le client while True: msg = input("Message pour le serveur: ") if msg == "quitter": # Sort de la boucle si on tape 'quitter' break sock.sendall(msg.encode()) data = sock.recv(1024) print("Serveur: {}".format(data.decode())) Le serveur while True: data = conn.recv(1024) if not data: # Sort de la boucle lorsque plus rien n'arrive break print("client: " + data.decode()) conn.sendall(data) E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 21 / 30
Overview 1 L’Internet 2 Les Protocoles Réseau 3 Le Protocole HTTP E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 22 / 30
Protocole HTTP Hyper Text Transfer Protocol (HTTP) Un protocole de communication client-serveur qui permet de récupérer et modifier des données présentes sur un serveur. Dans sa forme standard, il utilise le port 80. La communication peut être chiffrée en utilisant HTTPS (Secured) sur le port 443. Histoire des versions de HTTP HTTP 0.9 (1991) HTTP 2.0 (2015) HTTP 1.0 (1996) HTTP 3.0 (En cours d’élaboration) HTTP 1.1 (1999) ... E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 23 / 30
Uniform Resource Locator (URL) Le protocole HTTP identifie toutes les données par des URLs userinfo hostname port https://john.doe:password@www.example.com:123/forum/faq/?tag=net&cmd=new protocol authority path query protocol : hostname et port : Le protocole de transfert utilisé. Socket de connexion du serveur. authority : path : Les paramètres de connexion au serveur. Le chemin vers l’objet requis. userinfo : query : Les paramètres d’authentification. Les paramètres de la requête. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 24 / 30
HTTP Requêtes et Réponses Un client HTTP effectue des requêtes sur une URL et reçoit une réponse Requêtes Réponses GET : Récupère un objet 1xx : Information DELETE : Détruit un objet 100 : Continue 101 : Changement de protocole PUT : Crée un nouvel objet 2xx : Succès POST : Met à jour un objet 200 : Succès PATCH : Modifie un objet 201 : Création effectuée TRACE : Récupère les 3xx : Redirection modifications appliquées à l’objet 301 : Changement permanent d’URL OPTIONS : Récupère la liste des 4xx : Erreur du client méthodes supportée par le serveur 400 : Requête incorrecte CONNECT : Établi une connexion 404 : Objet non trouvé en vue de créer un canal chiffré 5xx : Erreur de serveur ... 500 : Erreur interne du serveur E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 25 / 30
Pratiquons un peu ! (1/2) 1 Ouvrez une console puis tapez les commandes suivantes : #> python -m http.server 8000 2 Connectez-vous sur votre propre machine avec un navigateur Web à l’URL : http://127.0.0.1:8000/ 3 Que constatez-vous sur votre navigateur Web ? 4 Que constatez-vous sur la console qui contient le serveur ? 5 Trouvez une explication aux messages qui sont apparus dans la console : 127.0.0.1 - - [18/Dec/2018 23:44:06] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [18/Dec/2018 23:44:06] "GET /favicon.ico HTTP/1.1" 404 - 127.0.0.1 - - [18/Dec/2018 23:44:06] code 404, message File not found 6 Créez ce fichier HTML (index.html) et visualisez le via le serveur Python : Titre de ma page Bonjour tout le monde! 7 Connectez-vous à votre machine en utilisant sa vraie adresse IP (pas ’127.0.0.1’). Quels changements constatez-vous sur la console ? E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 26 / 30
Pratiquons un peu ! (2/2) Un serveur web peut aller au-delà de la manipulation simple de fichiers. On peut considérer les URLs comme des commandes et programmer son serveur pour répondre à ces commandes (sans qu’il n’y ait de fichiers). Par exemple, des sites comme Google, Twitter ou même Facebook utilisent ce principe. 1 Créons la commande ’request’ : from http.server import HTTPServer, SimpleHTTPRequestHandler class MyHTTPRequestHandler(SimpleHTTPRequestHandler): def do_GET(self): if self.path == "/request": self.send_response(200) self.wfile.write('Bonjour tout le monde!'.encode()) else: self.send_error(404) httpd = HTTPServer(('localhost', 8080), MyHTTPRequestHandler) httpd.serve_forever() Ce serveur réagit normalement sauf sur l’URL ’http://localhost:8080/request’, alors il répondra en écrivant ’Bonjour tout le monde!’. 2 Remplacez le texte ’Bonjour tout le monde!’ par un fichier HTML valide. E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 27 / 30
Bibliothèque ’telnetlib’ (1/2) TelnetLib est une des bibliothèques de base qui permet de communiquer via le réseau (l’autre bibliothèque de Python pour cela est ’socket’, plus généraliste mais aussi plus difficile à utiliser). Ouvrir une connexion from telnetlib import Telnet HOST = '127.0.0.1' PORT = 23 tn = Telnet(HOST, PORT) Passer en mode interactif tn.interact() Fermer une connexion tn.close() E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 28 / 30
Bibliothèque ’telnetlib’ (2/2) Envoyer des données tn.write(b'Hello server!') Réceptionner des données En programmation, la réception de données est un problème car on est jamais sûr que la transmission est terminée. On doit attendre un signal qui marque la fin de la transmission (souvent un mot clé spécial ou une suite de caractères spécifiques). Cela force à envisager les programmes comme des entités ’asynchrones’. Voici les différentes méthodes pour réceptionner des données envoyées sur le réseau : Lis les données jusqu’à ce qu’il rencontre la chaîne d’octets b’fini!\n’. data = tn.read_until(b'fini!\n').decode('utf-8') Lis les données de manière bloquante (jusqu’à terminaison de la connexion) : data = tn.read_all().decode('utf-8') Lis les données de manière non bloquante : data = tn.read_some().decode('utf-8') E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 29 / 30
Substituons nous au Navigateur Web 1 Lancez votre serveur Web local avec la commande : #> python -m http.server 2 Écrivez le programme suivant : from telnetlib import Telnet HOST = '127.0.0.1' PORT = 8000 tn = Telnet(HOST, PORT) tn.interact() 3 Exécutez le programme que vous venez de taper et tapez la requête suivante : GET / HTTP/1.1 Host: 127.0.0.1 Connection: close 4 Qu’observez vous dans la console du serveur et dans celle du programme ? E. Fleury, D. Renault (LaBRI, France) Programmation Réseau en Python 8 janvier 2020 30 / 30
Vous pouvez aussi lire