[Tuto] Utiliser les fonctions TCP/IP

Espace contenant des tutoriels divers concernant AutoIt.
Règles du forum
.

Tutoriel "La programmation avec Autoit" : https://openclassrooms.com/fr/courses/1 ... vec-autoit
Répondre
Avatar du membre
blacksoul305
Membre émérite
Membre émérite
Messages : 957
Enregistré le : ven. 18 mars 2011 11:49
Localisation : Au pays des programmeurs.
Status : Hors ligne

[Tuto] Utiliser les fonctions TCP/IP

#1

Message par blacksoul305 »

Bonjour ou bonsoir chers/chères AutoItiens/AutoItiennes,

j'ai pendant longtemps voulu rédiger un tutoriel pour les débutants assez complet sur l'utilisation du protocole TCP/IP, en espérant pouvoir aider les personnes qui, comme moi, ont eu beaucoup de mal à appréhender ces commandes. A l'heure d'aujourd'hui, je n'ai pas beaucoup de temps pour attaquer des projets copieux, alors plutôt que de le "perdre", j'ai décidé de l'utiliser afin de rédiger ce petit tutoriel.

Je ne suis pas un développeur de métier, ni un pro de l'AutoIt, ainsi si des utilisateurs remarquent quelques notions pas tout à fait correctes, qu'ils en fassent part via commentaires ou messages privés pour que je puisse rectifier le tir. Maintenant que vous êtes avertis, il est temps pour nous de se lancer dans le vif du sujet !

Avant de nous lancer dans de la programmation réseau, partons déjà sur "un peu" de théorie :

Qu'est-ce que le TCP/IP ?

Le TCP/IP (Transmission Control Protocol/Internet Protocol) regroupe un ensembles de protocoles (disons des démarches bien spécifiques à suivre) afin d'utiliser Internet, entre plusieurs ordinateurs. Pour faire simple, ce sont l'ensembles de règles à respecter pour pouvoir programmer des applications ayant la capacité à utiliser Internet. La plupart du temps, cela nous sert à établir des "routes" dans lesquelles nous faisons passer des données Ces "routes" sont appelées "connexions".
(dans ce tutoriel j'utiliserai beaucoup de métaphores, non pas pour faire beau mais parce qu'il est plus simple de s'imaginer les choses dans des situations bien concrètes.).

Utilisation du TCP/IP dans le cas client/serveur :

Nous allons nous mettre dans un cas général quant à l'utilisation du TCP/IP, avec la connexion client-serveur basique. Commençons par définir ces deux mots.
Le "client" et le "serveur" sont deux programmes au fonctionnement plus ou moins proches. Dans le but de vous expliquer tout ça, je vais commencer avec une première métaphore, qui me permettra aussi de vous donner du vocabulaire précis.
Le "client" est le programme qui va "lancer" la conversation avec le serveur. Lorsqu'il est en train d'essayer, on parle de "tentative de connexion". Le "serveur" quant à lui peut avoir plusieurs réactions vis à vis de cette tentative de dialogue. Soit il l'accepte, et dans ces cas là on parle de "connexion", soit il la refuse, et là on parle de... rien du tout !
Une fois la discussion lancée (sous-entendu le "serveur" est d'accord), vous pouvez vous échanger des paroles, que l'on appelle "données", jusqu'à ce que l'un des deux programmes décide d'interrompre l'échange.

Maintenant vous savez comment fonctionne le client et le serveur entre eux, mais jusque là ils échangent tous les deux des données, pas trop de différences. On reconnaît le client au serveur car il s'agit du client qui lance une tentative de connexion en premier, et qui est par conséquent dépendant du serveur. Prenons l'exemple d'un serveur de jeu, WoW. Le serveur sur lequel vous vous trouvez, que vous vous connectiez ou pas, il fait quand même sa vie. En revanche essayer de couper la connexion Internet de votre ordinateur et tentez de lancer le client... vous ne pourrez pas faire grand chose sans le serveur.

Nous allons maintenant approfondir le sujet dans les deux prochaines parties qui vont suivre, en parlant du Processus de Connexion, et du Processus d'Echange de Données. Il va bien falloir suivre car le vocabulaire sérieux va tomber, ce n'est pas le moment de se perdre !


Le Processus de Connexion :

La connexion entre deux programmes, et je dirais même machines dans cette partie fait intervenir ce que l'on appelle les "sockets". Pour se les représenter, rien de mieux que de se dire qu'ils s'agissent de portes. Vous allez très vite comprendre pourquoi.
Considérons deux machines, A et B.
La machine A contient le programme client.
La machine B contient le programme serveur.
Faisons l'analogie maintenant.
Vous êtes devant une maison dans laquelle se déroule une fête, et vous aimeriez bien vous y inviter. Vous représenter la machine A. La maison dans laquelle se déroule la fête, c'est la machine B, et la fête, c'est le programme de la machine B.
En gros, voilà ce qu'il passe.
Pour rentrer, vous avez besoin de passer par la porte, ici c'est ce que l'on appelle un "socket", on va donc dire que l'on créée un socket. Vous, vous toquez à la porte et en faisant cela, vous créez un socket, c'est un peu comme si vous aviez l'intention de lancer une discussion en reprenant mon premier exemple en fait. Que se passe t-il de l'autre côté de la porte ? Vous avez de la chance, la fête est sympa puisqu'elle vous attend (dans notre cas précis bien sûr, car elle n'est pas obligée cf: exemple WoW). La fête a créé un socket elle aussi, qui est la même porte mais d'une autre manière, puisqu'elle à la place de toquer, elle va écouter à la porte. Ainsi, elle vous entend toquer... Nos deux cas de figures dont je vous avais parlé en début de tutoriel apparaissent ! Par conséquent, soit la fête décide de laisser la porte fermer, et aucune connexion ne se fait puisqu'en effet vous ne pouvez dialoguer à travers la porte, soit elle vous l'ouvre, et dans ces cas là vous avez établi une connexion ! Et bien sûr, à tout moment l'un peu mettre fin à la discussion en fermant la porte. Maintenant comment se passent la discussion ? C'est notre seconde partie !

Le Processus d'Echange de Données :

Cette partie va être plus courte puisque l'on va reprendre l'exemple précédent. Nous avons créé notre connexion (dialogue) entre le programme A et B, par l'intermédiaire de deux sockets. L'un créé en essayant de lancer une connexion (A), l'autre en essayant de la recevoir (B). La longue discussion tantôt parlée par A, tantôt par B est composée de plusieurs paroles :
"Tu fais une fête ?"
"Oui elle est trop cool"
Ces deux phrases, ce sont des données. Dans un champ lexical du réseau, on parlera de "paquet". Des "paquets de données". Une phrase prononcée par l'un n'est rien d'autre qu'un "paquet de données". Pour que chacun comprenne ce que l'autre dit, il faut d'abord décortiquer la phrase, là on parle "d'analyse de paquets". Et pour comprendre, il faut parler la même langue. Ici c'est vous qui créez votre propre langue, soit en cryptant vos données, soit en les organisant de telles et telles manières. Au final, deux programmes n'ayant pas la même façon de traiter des données ne peuvent communiquer entre eux. De plus, il est très important de créer une certaine structure dans vos paquets, tout comme il est très important de bien articuler lorsque l'on parle, pour éviter de mal se faire comprendre... dans ce type de programmes, c'est presque courant malgré ce que l'on pourrait en penser !

Nous avons terminé avec la théorie, il est donc temps de passer à la pratique. Une fois que vous aurez les exemples en tête, avec le vocabulaire et fonctions TCP associées, vous verrez que cela vous paraîtra beaucoup plus simple !



Côté pratique 1 : Création d'une connexion entre deux programmes :

Nous voici à notre premier point pratique de ce tutoriel, ici nous allons essayer d'établir une connexion. Pour cela, nous allons créer ensemble deux programmes en simultané (vous verrez que ça ne sera pas bien compliqué), et allons commencer par le serveur. (L'ordre dans lequel vous attaquez les programmes n'a pas réellement d'importance, même si je pense qu'il est plus simple de commencer par le serveur).

Le serveur, c'est le programme B, et si vous vous souvenez bien, il est censé écouter à la porte. Pour écouter à la porte, nous allons devoir utiliser la fonction "TCPListen", voyons ce qu'elle nous dit...

Code : Tout sélectionner

TCPListen(IPAddr, port)
Ah oui... en effet il y a des arguments dont je ne vous avais parlé... "to listen" en anglais est le verbe "écouter", et cette fonction va nous permettre de créer un socket. Ainsi vous avez bien compris que dans notre cas il s'agira d'un socket d'écoute.
Or si l'on reprend l'exemple de la fête à laquelle vous voulez vous inviter, vous allez sûrement tomber dans un quartier résidentiel avec plusieurs maisons, de plus, ces maisons ont beaucoup de portes alors laquelle choisir ?
Le premier argument est l'adresse IP (IP Address). Le problème, c'est qu'il y'en a plusieurs qui vous ont accessibles, et deux types différents :
L'adresse publique : il s'agit de l'adresse que tout le monde "voit", et qui est généralement réinitialisée à chaque fois que vous redémarrez votre routeur. Celle-ci s'obtient avec la fonction "_GetIP()" en utilisant le fichier include : "Inet.au3". Ayez la juste en tête pour l'instant car elle ne peut pas être utilisé côté serveur, c'est à dire pour ouvrir un socket d'écoute.
L'adresse IP de votre réseau : Que vous soyez connecté à votre box en filaire ou par wifi, vous avez forcément un périphérique réseau qui se cache derrière. C'est à ce dernier que la box va attribuer une adresse IP. Elle(s) est (sont) accessible(s) avec la maccro suivante "@IPAdressn =" avec n allant de 1 à 4.
Passons au second argument, le port. Le port est un numéro allant de 1 à  65 536. Les seules et uniques règles sont que :
Le port choisi ne doit pas être un port réservé par Windows
Le port ne dois pas être utilisé par un autre programme.
Le choix d'un port paraît donc compliqué, néanmoins, sachez que vous n'aurez pas de mal à trouver les bons ! Dans notre exemple, nous utiliserons le port 9989. Veuillez jeter un coup d'oeil au lien suivant si jamais vous voulez en savoir un peu plus sur les ports utilisés etc...

Liste des ports

Voici maintenant un code pour trouver votre adresse IP :

Code : Tout sélectionner

MsgBox(0,"IP","Adresse IP n°1 : " & @IPAddress1 & @CRLF & "dresse IP n°2 : " & @IPAddress2 & @CRLF & "Adresse IP n°3 : " & @IPAddress3 & @CRLF & "Adresse IP n°4 : " & @IPAddress4)
Retenez la maccro qui vous intéresse et passons au code (enfin) du serveur !

Commençons par déclarer les variables qui vont nous être utiles :

Code : Tout sélectionner

Global $mainSocket, $IP = @IPAddress1, $port = 9989, $max = 50  
;~ $mainSocket : qui va être l'ID de notre socket d'écoute si tout se passe bien !
;~ $IP : La variable qui va contenir votre adresse IP
;~ $port : La variable qui va contenir votre port 
;~ $max : Limite le nombre de connexions sur le socket d'écoute au nombre de cinquante
Maintenant nous allons créer notre socket d'écoute... ou plutôt vous allez me le créer. A l'aide des variables que nous avons déclarées ensemble, et le fichier d'aide de la fonction TCPListen. Correction ci-dessous !
► Afficher le texteCorrection
Remarque : en ce qui concerne les erreurs, sachez que les codes sont nombreux, mais on croise la plupart du temps comme problème un problème d'IP, de port déjà utilisé. Néanmoins, je vous conseille de garder ce lien sous le coude pour chaque projet réseau que vous vous donnerez : Liste des codes d'erreur

Maintenant passons au client, pour les variables, cela nous donne :

Code : Tout sélectionner

Global $socket, $IP = @IPAddress1, $port = 9989
Même consigne que pour le serveur, vous allez avec les variables et le fichier d'aide de TCPConnect créer la partie connexion du programme client ! Correction juste ci-dessous.
► Afficher le texteCorrection
Remarque : encore une remarque quant aux codes d'erreurs. Ce sont les mêmes que pour le serveur en revanche, le 1 et le 2 veulent dire respectivement : problème d'IP et problème de port.

Maintenant pour tester le fonctionnement de nos deux programmes, nous devons empiéter sur la seconde partie du transfert de données, car pour les associer, il va falloir les faire communiquer un minimum. Revenons au serveur.
En l'état, notre code ne nous permet seulement de créer un socket de connexion, mais une fois créé, le programme se quitte (et même pas proprement). Nous devons maintenant créer une partie supplémentaire qui n'existe pas sur le client, qui va s'occuper de vérifier s'il y a des connexions entrantes en vue, et de les accepter.

Remarque : Nous allons dans ce tutoriel nous limiter à n'accepter qu'une seule connexion. Néanmoins, une fois que vous maîtriserez un peu mieux la programmation réseau, rien ne vous empêchera de vous amuser à créer des serveurs multi-connexions. C'est même conseillé, car c'est un peu le but d'un serveur entre nous sois dit, n'est-ce pas ?

Trève de bavardage, programmons maintenant ! Puis qu'il s'agit de détecter des connexions entrantes, il nous faut mettre ça dans une boucle, que vous pourrez gérer par bien des façons : timer, limite de connexions pour les plus connues. Pour le tutoriel il me semble très approprié de prendre comme condition de sortie de boucle l'établissement d'une seule connexion, avec la fonction TCPAccept. Pour le coup nous pouvons ajouter une autre variable, que j'appellerai par abus de langage $socket. A vous de jouer, la correction est disponible ci-dessous.
► Afficher le texteCorrection
Il nous reste une dernière ligne droite avant de rendre le serveur partiellement fonctionnel. Seulement comme je l'ai dit, nous allons empiéter sur la partie de transmission de données. Ajoutons une autre variable $recv à notre joli paquet de bébêtes. Pour cette fois je vous déballe directement le code, vous devez juste vous en empreigner et le comprendre, je laisse le client devenir une de vos affaires à régler personnellement.
► Afficher le texteCorrection
Avec ce code là, on arrive à un serveur qui exécute la démarche de connexion proprement. Maintenant il va falloir que vous fassiez pareil (dans le sens terminer le programme) avec le client. Pour cela vous allez utiliser la fonction TCPSend. A vous de jouer !
► Afficher le texteCorrection
Compilons maintenant les programmes. Lançons d'abord le serveur puis ensuite le client !
Normalement, les deux programmes devraient fonctionner. Le plus important c'est que vous ayez compris la logique du TCP et la démarche à adopter pour la connexion de deux programmes entre eux. Si c'est le cas, à force cela deviendra instinctif et facile à faire !

Côté pratique 2 : Création d'un système de transmission de données client-serveur :

Pour cette partie, nous allons seulement parler de la transmission des données et de l'entretien de la connexion entre le serveur et le client. Je vous passerai certaines de mes astuces qui ont fait leur preuve, et vous mettrai au courant de certains problèmes que vous pourrez rencontrer. Après cette partie, et un peu de pratique bien sûr, vous serez en mesure d'utiliser le TCP/IP dans vos programmes de façons propres et efficaces ! Pour illustrer cette partie, nous allons reprendre les codes précédents et les modifier. Notre objectif va être d'envoyer des MsgBox personnalisées au serveur à partir du client. Avant de nous lancer dans la programmation des deux programmes, nous devons d'abord mettre au point les choses dont on va avoir besoin.

Notre serveur sera en mesure d'accepter une connexion et de recevoir des données envoyées par un client. Le programme client sera en mesure de se connecter sur le programme serveur et d'envoyer des données. Pour le coup tout ça on l'a fait dans la partie précédente, et ça marche plutôt bien. Maintenant allons un peu plus loin. Le client sera en mesure d'envoyer un ensemble d'arguments que le serveur pourra exploiter afin d'exécuter une commande. Là nous devons encore travailler un peu.

Faisons d'abord la mise au point sur les arguments d'une MsgBox. Il nous faut :
  • Un type
  • Un titre
  • Un message
D'accord. Mais comment vous vous y prendrez vous pour envoyer les données de façons à les rendre exploitables très facilement ? Vous ne voyez pas de quoi je veux parler, regardez l'exemple qui suit.

"Je veux une MsgBox de type information, avec un le titre 'Information' et le message 'Je suis un programme réseau.'."

Ainsi dans un paquet cela donnerait : "64InformationJe suis un programme réseau"
Pas très exploitable tout ça n'est-ce pas ?
Cela pourrait marcher avec un espace mais dans ces cas là on n'arriverait pas à avoir le texte complet derrière... On pourrait y arriver connaissant le nombre d'arguments mais ça serait très fastidieux. Ainsi je vais vous donner le symbole que j'utilise principalement en tant que séparateur, et celui qui est utilisé la plupart du temps (exemple les ComboBox) :"|". Il est disponible en utilisant le code ALT 124.
Du coup pour l'exemple ça pourra nous donner : "64|Information|Je suis un programme réseau"
Maintenant nous sommes prêt à passer à la pratique ! Commençons par le client qui sera beaucoup plus facile à terminer.

Vous allez créer le code qui permet la création d'une liste d'arguments, bien structurée, et l'envoie de cette dernière. Je vous propose une correction possible :

Modification de la boucle principale
► Afficher le texteCorrection
Une fois que le client est correctement programmé, nous pouvons passer au serveur. Pour analyser le paquet transmis par le client, nous allons utiliser la fonction StringSplit, qui renvoie un tableau avec le nombre d'arguments séparés par un certain caractère, et tous les arguments. Ainsi nous pourrons dissoscier chaque argument et les utiliser correctement. Là aussi je vous laisse programmer !

Modification de la boucle principale :
► Afficher le texteCorrection
Maintenant vous avez un client et un serveur qui marche tout deux du tonnerre ! Il y a une dernière critique que j'aimerais porter vis à vis de ce code, ou plutôt de la manière utilisée pour la structure des données. En effet, testé comme cela, le code fonctionne à tous les coups. En revanche, s'il y avait des données envoyées constamment par le client, ces dernières pourraient parasyter l'envoie d'une commande. Prenons pour exemple l'envoi perpétuel de "1" au serveur. Il se pourrait bien qu'une fois reçue, le paquet contenant les arguments de la MsgBox devienne :
"11111164|Information|Je suis un programme réseau1111111" Le paquet serait donc inexploitable. Pour palier à ce problème, j'utilise la structure suivante :
"start|commande|nombred'arguments|argument1|argument2|argumentn|end"
Le début et la fin du paquet sont connus et vu qu'ils ne rentrent pas en tant qu'argument, ils peuvent être parasytés sans pour autant mettre en péril la commande et faire planter le serveur !

Nous approchons donc de la fin du tutoriel. Certes il n'est pas très complet, mais il vous donne au moins quelques bonnes bases pour pouvoir attaquer la programmation réseau sans trop de prises de tête ! J'essayerai d'ajouter des éléments, mais je ne promets rien vu le temps dont je dispose. Je suis néanmoins ouvert à toutes critiques ou remarques quant au sujet de ce tutoriel. De plus si je ne peux répondre à vos soucis très rapidement, je suis certain que vous pourrez avoir de bonnes et rapides indications de la part des utilisateurs expérimentés de ce forum.

Je vous souhaite une bonne programmation, et à bientôt !

EDIT : je retirerai la coloration syntaxique, je pensais qu'elle était autorisée pour les tutoriels aussi, désolé !

EDIT 2 : fait !

EDIT 3 : Coloration syntaxique rajoutée !
Fichiers joints
Codes source.zip
Contient le code source pour les IPs, et les codes sources client/serveur des Côtés Pratiques 1 et 2. (Archive ZIP).
(3.5 Kio) Téléchargé 836 fois
Modifié en dernier par blacksoul305 le dim. 01 déc. 2013 21:31, modifié 1 fois.
Étudiant en 2ème année de Licence Informatique.
Avatar du membre
Tlem
Site Admin
Site Admin
Messages : 11773
Enregistré le : ven. 20 juil. 2007 21:00
Localisation : Bordeaux
Status : Hors ligne

Re: [Tuto] Utiliser les fonctions TCP/IP

#2

Message par Tlem »

Bonsoir et merci pour ce tutoriel.
Je ne sais pas qui a dit que la coloration syntaxique n'était pas autorisé dans la section Tutoriels, car moi même et la plupart des modérateurs l'utilisons, donc si vous le souhaitez, vous pouvez la remettre. ^^
Thierry

Rechercher sur le forum ----- Les règles du forum
Le "ça ne marche pas" est une conséquence commune découlant de beaucoup trop de raisons potentielles ...

Une idée ne peut pas appartenir à quelqu'un. (Albert Jacquard) tiré du documentaire "Copié n'est pas volé".
Avatar du membre
TT22
Membre émérite
Membre émérite
Messages : 1566
Enregistré le : lun. 18 avr. 2011 15:21
Localisation : La Quatrième Dimension
Status : Hors ligne

Re: [Tuto] Utiliser les fonctions TCP/IP

#3

Message par TT22 »

Salut, je trouve ton tutoriel assez bien construit et compréhensible. Je pense qu'il pourra être très utiles aux débutants TCP/IP.

J'ai néanmoins quelques remarques à faire...
  • Tout d'abord je pense qu'il serait utile de rappeler la différence entre Internet et le World Wide Web dans la partie "Qu'est-ce que le TCP/IP ?" car au départ certains risquent de confondre.
  • Ensuite, ta métaphore de la discussion pour le client/serveur est certes très compréhensible, mais ne serait-il pas plus simple d'utiliser la métaphore client/serveur ? (le client passe une commande au serveur et le serveur lui sert quelque chose (ou pas))
  • Puis, vers la fin du paragraphe "Côté pratique 1" tu dit de compiler le programme mais ce n'est pas obligatoire.
  • Je pense qu'il serait également utile de préciser que le serveur peut rencontrer des problèmes lors de l'écoute si un par-feu est activé.
  • Enfin, tu ne montre pas d'exemple où le serveur répond au client (par exemple le code de retour de la MsgBox) ce qui laisse en arrière plan le fait qu'un serveur peut retourner des données (ce qui est quand même le principe de base du HTTP).
Et à titre personnel, plutôt que d'utiliser des '|' pour séparer les arguments des mes échanges TCP/IP, j'utilise une ligne de commande/statut puis une ligne par paramètre comme dans les en-têtes HTTP (et remplace les sauts de lignes dans les paramètres par des '\n').

Sinon, beau travail et merci pour ce partage.
Cordialement,
TT22
Avatar du membre
blacksoul305
Membre émérite
Membre émérite
Messages : 957
Enregistré le : ven. 18 mars 2011 11:49
Localisation : Au pays des programmeurs.
Status : Hors ligne

Re: [Tuto] Utiliser les fonctions TCP/IP

#4

Message par blacksoul305 »

Bonsoir,

il me semblait bien que la coloration syntaxique était autorisée pour les tutoriels mais j'ai préféré faire une recherche pour vérifier. Dans le message de Timmalos à ce sujet le forum tutoriel n'était pas mentionné, du coup j'ai choisi la voie de la sûreté haha !

Merci et bonne soirée !

EDIT : Salut TT22, je prends en note tes remarques. J'essayerai de modifier certaines choses le plus tôt possible mais je ne promets rien d'ici mercredi. Juste pour revenir sur certains points, il est vrai que la métaphore que yu proposes est on ne peut plus logique, je ne sais pas pourquoi je n'ai pas pioché directement celle là... Sinon quand je préconise de compiler les programmes pour les tester, c'est parce que d'après mes expériences, il n'est pas possible de debugger deux programmes simultanément. Alors quitte à compiler l'un, autant faire l'autre !
J'essayerai de rajouter comme tu me l'as conseillé un retour de la part du serveur, puisqu'en effet un serveur qui ne répond pas, c'est bizarre. Enfin je verrai pour rajouter une partie remarque dans laquelle je mettrai des certaines nuances comme celle du pare-feu.

Merci pour la considération que vous portez tous les deux àa ce tutoriel, bonne nuit !
Étudiant en 2ème année de Licence Informatique.
Avatar du membre
DimVar
Niveau 10
Niveau 10
Messages : 867
Enregistré le : ven. 30 mai 2008 15:08
Status : Hors ligne

Re: [Tuto] Utiliser les fonctions TCP/IP

#5

Message par DimVar »

Merci pour ce tutoriel.

Je pense que tu aurais pu gagner du temps - pléonasme puisqu'on est sur un forum de scripting - en faisant un schéma pour les bases TCP/IP ou en renvoyant vers de l'existant (tuto du zero sur TCP/IP).

Cdlt.
N'évoquons pas la pierre, les jeunes risqueraient d'en poire !
Sharkou
Niveau 1
Niveau 1
Messages : 1
Enregistré le : mer. 11 févr. 2015 22:48
Status : Hors ligne

Re: [Tuto] Utiliser les fonctions TCP/IP

#6

Message par Sharkou »

Merci beaucoup pour ton tuto, ça m'a beaucoup aidé :)
Répondre