La programmation réseau en Python

a marqué ce sujet comme résolu.

Salut,

Je mets ce tuto très très tôt en bêta pour recueillir des idées et des retours sur son plan.

J’ai dans l’idée de proposer un cours de programmation réseau en deux parties, la première introduisant les bases et l’approche "classique", et la seconde portant plus spécifiquement sur asyncio. Actuellement, les (titres des) chapitres ont tous trait à la façon de gérer des connexions (sockets, socketserver, les deux API d’asyncio), je n’exclus pas, au besoin, de rajouter des chapitres sur l’écriture de parseurs ou de machines à états.

J’aurais surtout besoin d’idées d’exemples et de TP.

  • J’ai déjà dans la tête un projet fil-rouge qui consisterait à implémenter un sous-ensemble du protocole IRC (c’est-à-dire, en considérant qu’il y a un serveur unique, et donc en virant du protocole tout ce qui touche à l’inter-connexion entre serveurs). Mais on ne peut décemment pas partir sur cet exemple dès le départ parce qu’il n’est pas faisable tant qu’on ne sait pas comment gérer proprement des connexions concurrentes.

  • J’ai aussi comme projet de faire une implémentation du protocole nailgun parce que sa state-machine est assez limitée (deux états).

Mais je suis preneur si vous avez d’autres exemples intéressants de protocoles plus simples (query/response…) et assez intéressants sur lesquels travailler le temps d’un chapitre à la fois.


Tout le monde se secoue ! :D

J’ai commencé (dimanche 15 janvier 2017 à 12h01) la rédaction d’un tutoriel au doux nom de « La programmation réseau en Python » et j’ai dans l’objectif de proposer en validation un texte aux petits oignons. Je fais donc appel à votre bonté sans limite pour dénicher le moindre pépin, que ce soit à propos du fond ou de la forme. Vous pourrez consulter la bêta à votre guise à l’adresse suivante :

Merci !

+5 -0

Salut,

Pour le plan, il me semble bien abordé, même si le chapitre I.2. est pour l’instant assez flou (je suppose que c’est là que seront introduits les notions de client, de serveur, de socket, et la mise en œuvre, ça fait peut-être un peu lourd).

J’aime bien le fait que tu débutes par l’explication de ce qu’est un protocole, en t’appuyant sur un exemple concret. Ça change en effet des cours qui en viennent directement à faire communiquer deux programmes sans vraiment expliquer pourquoi ni comment.

Quand au(x) TP, tu dois pouvoir commencer par une implémentation basique d’IRC où seul un client pourrait se connecter (mais les opérations sont alors bien limitées). Ou partir sur une implémentation d’HTTP dans un premier temps, c’est facile à mettre en place et ça donne des résultats exploitables. Tu garderais alors IRC pour la suite, de façon à montrer les multiples clients et les canaux de données.

Salut,

Pour le plan, il me semble bien abordé, même si le chapitre I.2. est pour l’instant assez flou (je suppose que c’est là que seront introduits les notions de client, de serveur, de socket, et la mise en œuvre, ça fait peut-être un peu lourd).

Je suis d’accord. Je n’exclus pas de scinder ce chapitre en plusieurs parties. Cela dit j’ai bien envie de mettre les mains dans du code le plus tôt possible… Je n’ai pas encore trop réfléchi à la façon dont j’allais m’y prendre mais peut-être qu’en effeuillant le sujet et en entrant progressivement dans les détails au fur et à mesure que l’on complexifie le code (plutôt que d’expliquer une étape après l’autre), ça peut marcher.

J’aime bien le fait que tu débutes par l’explication de ce qu’est un protocole, en t’appuyant sur un exemple concret. Ça change en effet des cours qui en viennent directement à faire communiquer deux programmes sans vraiment expliquer pourquoi ni comment.

C’est en effet une lacune de tous les cours que j’ai pu voir. Typiquement, je ne me rappelle pas avoir lu le moindre cours de programmation réseau qui m’explique comment implémenter une machine à états ou un parseur. Pire encore : même si ce n’est expliqué dans aucun cours, sa maîtrise reste indispensable pour ne pas se perdre dans des docs techniques comme celle de l’API Transport/Protocol d’asyncio.

Quand au(x) TP, tu dois pouvoir commencer par une implémentation basique d’IRC où seul un client pourrait se connecter (mais les opérations sont alors bien limitées). Ou partir sur une implémentation d’HTTP dans un premier temps, c’est facile à mettre en place et ça donne des résultats exploitables. Tu garderais alors IRC pour la suite, de façon à montrer les multiples clients et les canaux de données.

entwanne

J’ai pensé à HTTP, mais je trouve ce proto un peu bordélique et j’ai peur de ne pas arriver à un résultat satisfaisant pour un tuto. À la base, j’aimais bien l’idée d’écrire un serveur qui répond tout le temps la même page, et de m’y connecter directement avec mon navigateur web, parce que ça envoie un wow-effect assez sympa. Mais en prenant une petite demi-heure pour mettre ça en place, je me suis aperçu que j’avais sous-estimé la quantité d’explications à fournir pour arriver à ce simple résultat.

D’autre part l’idée de HTCPCP de Kje me fait bien marrer !

Après il est tout à fait possible de faire les deux, hein. On peut parfaitement faire un micro-serveur HTTP dans le TP sur les sockets, et implémenter HTCPCP avec socketserver ou bien un client et un serveur complets avec l’API Stream d’asyncio.

Une autre idée qui m’est venue entre temps, ce serait TFTP, qui a le double avantage d’être très simple (beaucoup plus petit que FTP), et basé sur des datagrammes, pour changer. ;)

+0 -0

L’avantage c’est qu’un chapitre sur 2 est un TP. Je me dis qu’avec un plan pareil, j’ai une carotte pour chaque chapitre en mode "allez, dès que j’ai fini de taper ce truc, je peux faire du code pour me rafraîchir".

… Blague à part, oui, le plan est gargantuesque, j’espère arriver au bout.

+0 -0

Hmmm, il m’est venu une idée saugrenue : quitte à démarrer sur du bas niveau, pourquoi ne pas envisager un exemple avec des sockets qui consiste à n’utiliser ni du TCP, ni de l’UDP, mais directement une socket IP raw pour implémenter le protocole ICMP ? :)

Je note l’idée dans un coin. Ça peut être rigolo à faire :

  • ça apporte des connaissances bas niveau sur le fonctionnement des sockets,
  • c’est un protocole typiquement binaire, donc qui permet d’aborder le parsing de flux binaires (avec le module struct),
  • … pour la culture, ça montre ce qui se passe derrière un ping !

@Kje: Oui c’est le but : dès que le contenu est exploitable, je le fais valider, quitte à mettre le tuto régulièrement à jour à raison d’un chapitre + un TP par itération.

+1 -0

Hmmm, il m’est venu une idée saugrenue : quitte à démarrer sur du bas niveau, pourquoi ne pas envisager un exemple avec des sockets qui consiste à n’utiliser ni du TCP, ni de l’UDP, mais directement une socket IP raw pour implémenter le protocole ICMP ? :)

nohar

Ce serait intéressant de faire ça quelque part dans le cours, mais pour démarrer je trouverais ça trop déroutant.

J’ai commencé à travailler sur le chapitre I.2. En réalité, je pense avoir trouvé le bon équilibre entre code et explications. Celui-ci va s’articuler avec :

  • Une première section qui explique les généralités (ce que sont les sockets, les familles et les types de connexions),
  • Pour chaque type de connexion (stream, datagram, raw), une section qui explique comment ça fonctionne (par exemple stream est un mode connecté et présuppose un schéma client-serveur, datagram est un mode non-connecté s’utilise avec sendto et recvfrom, et raw… existe, quitte à garder un exemple pour plus tard).
  • Dans chacune des sections stream et datagram, on implémente un petit echo server qui sert globalement à illustrer toutes les méthodes inhérentes au type de connexion.

C’est pas sorcier en fait… À condition de prendre le temps de faire des dessins. :)


Bonjour les agrumes !

La bêta a été mise à jour et décante sa pulpe à l’adresse suivante :

Merci d’avance pour vos commentaires.

+0 -0

J’ai rempli l’essentiel du chapitre 2.

Reste plus qu’à faire les schémas des 2 premiers chapitres et rajouter les explications qui vont bien et je pourrai passer au premier TP. :)


Bonjour les agrumes !

La bêta a été mise à jour et décante sa pulpe à l’adresse suivante :

Merci d’avance pour vos commentaires.

+0 -0

Comme le dit Kje, le scope de ce tuto se limite, grosso-modo, à ce qu’on peut faire avec la bibliothèque standard, et comment fonctionnent les programmes en réseau d’une façon générale.

On peut envisager des articles/tutos indépendants sur telle ou telle bibliothèque de message-queue… Mais l’idée de ce tuto c’est plutôt que les gens deviennent capables de comprendre comment marchent ces bibliothèques sans avoir besoin de tuto supplémentaire.

+0 -0

Salut,

Super projet! Je viens de parcourir le chapitre 2. Une chose me chifonne. Tu ne parles pas vraiment du fait que si on veut envoyer des données sur un socket, sock.send(MESSAGE.encode()) ne garantit pas que tout soit envoyé. De même pour la réception, msg = sock.recv(BUFFER_SIZE) ne garantit en rien que l’entièreté du message est reçu.

Bon en réseau local, c’est sûr que ça semblera fonctionner toujours. Mais je vois très souvent les débutants trébucher sur cette particularité.

Je me doute que ce n’est que le début du tutoriel. Mais en lisant le reste de la structure proposée, je ne vois pas trop où tu vas parler de ça.

Aussi ce serait peut-être bien d’expliquer les avantages et inconvénients des sockets TCP vs UDP. Expliquer pourquoi on choisit l’un plutôt que l’autre selon ce qu’on veut réaliser. Je lève souvent un sourcil quand je lis sur certains forums quelqu’un conseiller d’utiliser de l’UDP car c’est plus rapide, sans aucune autre explication. Et c’est souvent accompagné du message: "Et ça marche super chez moi!". :) C’est sûr qu’en réseau local, ça marche d’enfer. Bref pour ce genre de personnes, des explications quant aux pour et contre entre UDP et TCP seraient bénéfiques, je pense.

EDIT Je vois que pour ce dernier point, c’est en fait pas mal abordé dans le chapitre précédent. Sorry. :)

+0 -0

Salut,

Super projet! Je viens de parcourir le chapitre 2. Une chose me chifonne. Tu ne parles pas vraiment du fait que si on veut envoyer des données sur un socket, sock.send(MESSAGE.encode()) ne garantit pas que tout soit envoyé. De même pour la réception, msg = sock.recv(BUFFER_SIZE) ne garantit en rien que l’entièreté du message est reçu.

Bon en réseau local, c’est sûr que ça semblera fonctionner toujours. Mais je vois très souvent les débutants trébucher sur cette particularité.

C’est pas tellement une question d’être en local ou non, mais plutôt que la payload dépasse la taille d’une simple trame IP.

Dans l’exemple de ce chapitre, je préfère ne pas m’occuper de ça et considérer que le message, Hello, World!, est de toute façon suffisamment petit pour qu’il passe sur un seul segment TCP (ou un seul datagramme UDP). Par contre en effet je vais devoir expliquer ça (et montrer une façon performante de recevoir les données en entier et dans un buffer, ainsi que l’envoi avec sock.sendall(data)) dans les TP qui vont suivre. J’évite juste de noyer le lecteur sous un trop grand nombre d’infos à la fois : quand on voit la complexité de base d’une communication connectée en TCP, je préfère que le lecteur pige d’abord ce schéma plutôt que lui prendre la tête sur des tailles de buffer et de trames réseau pour un simple Hello World.

Dans le tout premier exemple TCP, j’ai déjà la ligne sock.setsockop(SOL_SOCKET, SOCK_REUSEADDR, 1) qui vient polluer la présentation avec une considération purement technique sur la fermeture des ports en TIME_WAIT

Bref, pas d’inquiétude, non seulement j’ai prévu de prendre ce fait en considération lors de l’envoi ou la réception des données, mais également dans l’écriture des parseurs.

Je me doute que ce n’est que le début du tutoriel. Mais en lisant le reste de la structure proposée, je ne vois pas trop où tu vas parler de ça.

Il y a au moins 5 TP de prévus dans ce tutoriel, je ne me fais pas trop de soucis pour ça.

Aussi ce serait peut-être bien d’expliquer les avantages et inconvénients des sockets TCP vs UDP. Expliquer pourquoi on choisit l’un plutôt que l’autre selon ce qu’on veut réaliser. Je lève souvent un sourcil quand je lis sur certains forums quelqu’un conseiller d’utiliser de l’UDP car c’est plus rapide, sans aucune autre explication. Et c’est souvent accompagné du message: "Et ça marche super chez moi!". :) C’est sûr qu’en réseau local, ça marche d’enfer. Bref pour ce genre de personnes, des explications quant aux pour et contre entre UDP et TCP seraient bénéfiques, je pense.

EDIT Je vois que pour ce dernier point, c’est en fait pas mal abordé dans le chapitre précédent. Sorry. :)

Dan737

J’ajoute que c’est pas quelque chose qu’on peut vraiment expliquer une bonne fois pour toutes sans y revenir. C’est une de ces notions où il vaut mieux avoir écrit à la fois des protocoles au-dessus de TCP et d’UDP pour bien s’en rendre compte.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte