Cours et exercices Programmation socket en ruby
...
Sockets en Ruby : client TCP
1 Nous allons utiliser la bibliothèque ’socket’
2 TCPSocket.open renvoie un objet client qui est ensuite utilisé pour gérer la connexion
3 Si la connexion est bien établie, l’objet client permet de communiquer via des méthodes comme gets ou puts
4 La connexion doit être fermée
1 r e q u i r e ’ so c ket ’
2 c l i e n t = TCPSocket . open ( " 1 2 7. 0. 0. 1 " , 1234)
3 c l i e n t . put s ( " S a l ut " ) ; c l i e n t . put s ( "Au r e v o i r " )
4 c l i e n t . c lo se ( )
Sockets en Ruby : serveur TCP
La classe TCPServer permet de construire un serveur (via TCPServer.open)
Ce serveur doit “accepter” un client qui se connecte
Résultat : un objet session de connexion socket serveur ↔ socket client
L’objet résultant permet de recevoir des données (via gets) ou bien d’envoyer (puts)
1 # ! / u s r / b i n / ruby
2 r e q u i r e ’ so c ket ’
3 s e r v e r = TCPServer . open(1234 )
4 se s sion = s e r v e r . accept ( )
5 put s ( se s sion . get s ( ) )
6 se s sion . put s ’ Bien recu ’
7 se s sion . c lo se ( )
Sockets en Ruby : client UDP
Le client UDP est différent du client TCP. Voici quelques opérations
Création socket local via UDPSocket.new
“Connexion” à une socket UDP distant pas une vraie connexion comme pour TCP cette opération fait le nécessaire pour pouvoir envoyer/recevoir des données
Le port local est disponible via l’attribut addr
Envoi et réception de données via send()/recvfrom()
1 # ! / u s r / b i n / ruby
2 r e q u i r e ’ so c ket ’
3 maSocketUdp = UDPSocket . new
4 maSocketUdp . connect ( " 1 2 7. 0. 0. 1 " , 1234)
5 put s maSocketUdp . addr [ 1 ]
6 maSocketUdp . send ( " aaa " , 0 )
7 put s maSocketUdp . re c vf rom ( 1 0 0 , 0 )
8 maSocketUdp . c lo se
Sockets en Ruby : serveur UDP
On utilise toujours un objet UDPSocket : la méthode bind() associe la socket UDP à un port local
IP local : 0.0,0,0, port à votre choix
Réception de messages : recvfrom (pas de gets() comme pour TCP) → un tableau à deux positions : pos 0 Le message : une chaîne de caractères
pos 1 Informations sur l’émetteur : tableau à 4 positions :[0] type adresse, [1] port, [2] nom, [3] ip émetteur
1 r e q u i r e ’ so c ket ’
2 sockUdp = UDPSocket . open ( )
3 sockUdp . bind ( " 0 . 0 . 0 . 0 " , 1234)
4 f o r i i n 1 . . 5 do
5 msg = sockUDP. re c vf rom ( 1 0 0 , 0 )
6 put s "Recu msg de "+msg [ 1 ] [ 3 ] + " : "+msg [ 0 ]
7 end
8 sockUdp . c lo se ( )
16/48
Sockets en Ruby : UDP en diffusion
Pour pouvoir envoyer des paquets en diffusion, l’objet
UDPSocket doit activer l’option Socket::SO_BROADCAST
Méthode utilisée : setsockopt(niveau,option,valeur)
niveau=Socket::SOL_SOCKET – modifications au niveau de la socket (et non pas SOL_TCP, SOL_UDP) option=Socket::SO_BROADCAST et valeur=true
L’adresse de diffusion est disponible via ifconfig
1 r e q u i r e ’ so c ket ’
2 sockUdpBCast = UDPSocket . new
3 sockUdpBCast . set so c kopt ( Socket : :SOL_SOCKET, Socket : :SO_BROADCAST, t r u e )
4 sockUdpBCast . connect ( " 172.31.25.255 " , 1234)
5 sockUdpBCast . send ( " S a l ut l e monde" , 0 )
6 sockUdpBCast . c lo se ( )
Méthodes importantes (bibliothèque socket)
Socket.gethostname() : le nom de la machine locale
Socket.getservbyname(nomService) : renvoie le port associé au service nomService
Socket.getnameinfo(domain,port,ip) : renvoie des
informations sur la socket : ip:port
Exemple : Socket.getnameinfo(["AF_INET", ’23’, ’88.221.216.34’]) "AF_INET" indique le fait qu’il s’agit d’une adresse IPv4 (Internet)
Socket.getaddrinfo(nommachine, service) : renvoie des informations numériques (l’IP) par rapport au service
service et la machine nommachine.
Exemple : Socket.getaddrinfo(’…’, ’http’)
Résumé des sockets
Sockets TCP
client Exemple : session=TCPSocket.open(...)
serveur Deux opérations : open et accept
serv=TCPServer.open(...)
session=serv.accept()
utilisation session.puts(...) et session.gets(...)
Sockets UDP
client Création objet et connexion à distance (pas une vraie connexion comme pour
TCP)
sockUDP=UDPSocket.new
sockUDP.connect(...)
serveur Deux opérations : open et bind
sockUDP=UDPSocket.open()
sockUDP.bind(...)
utilisation sockUdp.send(...) ou sockUdp.recvfrom
Le flux du programme : paradigme classique
Paradigme séquentiel
Un programme = une séquence d’instructions en série :
1 a=b
2 c=a*a-a
3 puts(Math.log(c))
4 .....
1 toute erreur peut provoquer un crash du programme
2 pas possible de gérer plusieurs clients au même temps
3 l’interaction avec l’utilisateur est programmée en avance l’utilisateur intervient uniquement lorsqu’on arrive à une instruction
comme gets()
Le programme ci-dessus cache une erreur
La valeur de c peut être négative : a < 1 ⇒ a × a − a < 0
Le flux du programme : paradigme classique
Paradigme séquentiel
Un programme = une séquence d’instructions en série :
1 a=b
2 c=a*a-a
3 puts(Math.log(c))
4 .....
1 toute erreur peut provoquer un crash du programme
2 pas possible de gérer plusieurs clients au même temps
3 l’interaction avec l’utilisateur est programmée en avance l’utilisateur intervient uniquement lorsqu’on arrive à une instruction
comme gets()
Le programme ci-dessus cache une erreur
La valeur de c peut être négative : a < 1 ⇒ a × a − a < 0
Le flux du programme : nouveau paradigme
Paradigme non-séquentiel
La programmation graphique/réseau change par rapport à la programmation "classique" séquentielle
Exceptions définir la réaction aux conditions exceptionnelles rencontrées pendant l’exécution du programme
Événements définir la réaction différents événements (un clic de souris)
Fils d’exécutions (threads) permettre l’exécution de plusieurs routines au même temps (ex. plusieurs clients)
… … …
Exercice 1 : Transferts UDP
Le protocole UDP utilise des paquets appelés "datagrams" pour effectuer des communications de façon non-fiable en mode non-connecté. Cela signifie qu’il n’est pas possible de savoir si les datagrams envoyés ont bien été reçus et qu’il n’est pas possible de savoir si les datagrams reçus l’ont été dans le bon ordre.
Dans cet exercice nous allons écrire deux programmes qui s’échangent une chaîne de caractère en utilisant le pro-tocole UDP. Le programme source envoie une chaîne de caractère à l’adresse IPv4 et au numéro de port spécifiés sur la ligne de commande au lancement du programme. De même, le programme récepteur réceptionne la chaîne de caractère envoyée et l’affiche à l’écran. Le numéro de port utilisé par le récepteur doit être passé en paramètre au lancement du programme.
Exercices :
Exercice 2 : Transferts TCP
Le protocole TCP utilise des paquets appelés "segments" pour effectuer des communications de façon fiable en mode connecté. Cela signifie qu’une application utilisant TCP donne l’assurance que tous les segments envoyés sont reçus et que ces segments sont reçus dans le bon ordre.
Cet exercice reprend l’exercice précédent en utilisant le protocole TCP.
Exercice 3 : Dialogue avec un serveur existant
On souhaite réaliser un petit navigateur web (très simplifié) en mode texte. Pour ce faire, vous allez réaliser en ruby un client TCP. Ce client devra pouvoir se connecter en TCP sur le serveur web dont le nom (e.g. www.google.fr) sera passé sur la ligne de commande au lancement du programme. Une fois connecté, votre programme devra récupérer et afficher dans le terminal la page web qui aura été spécifiée sur la ligne de commande (e.g. index.html). On rappelle que les échanges de page web se font à l’aide du protocole HTTP (pour Hyper Text Transfer Protocol). Le port de communication par défaut d’un serveur web est le port numéro 80. La spécification du protocole HTTP se trouve dans le RFC (Request For Comments) 2068. Ce RFC est disponible à l’adresse suivante : Votre client ne devra supporter que la commande GET du protocole HTTP. La commande telnet m p établie une connexion TCP sur le port p de la machine m permettant alors de tester le protocole HTTP.
Exercice 4 : Talk multi-utilisateurs
On souhaite réaliser un système client/serveur permettant de communiquer à plusieurs simultanément sur le réseau. Le programme client devra au préalable se connecter au serveur, puis récupérer les chaînes de caractère entrées par l’utilisateur sur l’entrée standard et les envoyer au serveur. A la réception d’une chaîne de caractère, le serveur doit prendre en charge l’envoi de cette chaîne à tous les clients connectés au serveur, sauf au client dont la chaîne est originaire. L’implémentation se fera à l’aide du protocole TCP.
Exercices :
Nous allons maintenant nous intéresser au client: