Programmation de sockets en Ruby

Ruby offre deux niveaux d'accès aux services réseau. Au niveau bas, vous pouvez accéder au système d'exploitation, ce qui vous permet de mettre en œuvre une prise en charge des sockets de base pour les clients et les serveurs pour les protocoles orientés connexion et sans connexion.

Ruby offre une prise en charge unifiée des protocoles réseau applicatifs tels que FTP, HTTP, etc.

Que ce soit de haut niveau ou de bas niveau, Ruby fournit quelques classes de base qui vous permettent d'interagir avec de nombreux protocoles tels que TCP, UDP, SOCKS, sans être lié à la couche réseau. Ces classes fournissent également des classes utilitaires qui vous permettent de lire et d'écrire facilement vers des serveurs.

Ensuite, apprenons comment faire de la programmation de sockets en Ruby.


Que sont les sockets

Lorsque la couche application communique avec la couche transport pour la communication de données, TCP et UDP rencontrent le problème de fournir des services concurrents à plusieurs processus d'application en même temps. Plusieurs connexions TCP ou plusieurs processus d'application peuvent avoir besoin de transmettre des données via le même port de protocole TCP. Afin de distinguer les différents processus d'application et connexions, de nombreux systèmes d'exploitation informatiques fournissent une interface appelée socket pour que les applications interagissent avec les protocoles TCP/IP, distinguant la communication réseau et les connexions entre différents processus d'application.

La création d'un socket implique principalement trois paramètres : l'adresse IP de destination pour la communication, le protocole de la couche transport utilisé (TCP ou UDP) et le numéro de port utilisé. Le sens original de Socket est "socket". En combinant ces trois paramètres et en les liant à un "socket", la couche application peut utiliser l'interface socket avec la couche transport pour distinguer la communication provenant de différents processus d'application ou connexions réseau, permettant des services de transmission de données concurrents.

Termes de socket :

OptionDescription
domainIndique la famille de protocoles utilisée, généralement PF_INET, PF_UNIX, PF_X25, etc.
typeSpécifie le type de socket : SOCK_STREAM ou SOCK_DGRAM. L'interface Socket définit également des sockets bruts (SOCK_RAW), permettant aux programmes d'utiliser des protocoles de plus bas niveau.
protocolGénéralement attribué à 0.
hostnameIdentifiant de l'interface réseau :
  • Chaîne, peut être un nom d'hôte ou une adresse IP
  • Chaîne "<broadcast>", spécifie l'adresse INADDR_BROADCAST.
  • Chaîne de longueur zéro, spécifie INADDR_ANY
  • Un entier, interprété comme une adresse binaire dans l'ordre des octets de l'hôte.
portport est le numéro du port. Chaque serveur écoute sur un ou plusieurs numéros de port pour les connexions client. Un numéro de port peut être un numéro de port Fixnum, ou une chaîne contenant le nom du serveur et le port.

Client simple

Ci-dessous, nous avons écrit un exemple de client simple utilisant un hôte et un port donnés. La classe Ruby TCPSocket fournit la méthode open pour ouvrir un socket.

TCPSocket.open(hosname, port) ouvre une connexion TCP.

Une fois que vous ouvrez une connexion Socket, vous pouvez y lire comme avec un objet IO. Lorsque vous avez terminé, vous devez fermer la connexion comme vous fermeriez un fichier.

L'exemple suivant montre comment se connecter à un hôte spécifié, lire les données du socket et enfin fermer le socket :

Exemple

require 'socket' #Sockets est la bibliothèque standard hostname = 'localhost' port = 2000 s = TCPSocket.open(hostname, port) while line = s.gets #Lire chaque ligne de données du socket puts line.chop #Imprimer sur le terminal end s.close #Fermer la socket

Serveur simple

En Ruby, vous pouvez utiliser la classe TCPServer pour écrire un service simple. Un objet TCPServer est un objet fabrique pour TCPSocket.

Maintenant, nous utilisons TCPServer.open(hostname, port) pour créer un objet TCPServer.

Ensuite, appelez la méthode accept de TCPServer. Cette méthode attend qu'un client se connecte au port spécifié, puis renvoie un objet TCPSocket représentant la connexion à ce client.

Exemple

require 'socket' #Obtenir la bibliothèque standard socket server = TCPServer.open(2000) #La socket écoute sur le port 2000 loop { #Exécuter le service indéfiniment client = server.accept #Attendre la connexion d'un client client.puts(Time.now.ctime) #Envoyer l'heure au client client.puts "Fermeture de la connexion. Au revoir !" client.close #Fermer la connexion client }

Maintenant, exécutez le code ci-dessus sur le serveur et observez l'effet.


Service TCP multi-client

Sur Internet, la plupart des services ont un grand nombre de connexions client.

La classe Thread de Ruby peut facilement créer des services multi-thread. Un thread gère les connexions client, tandis que le thread principal attend d'autres connexions.

Exemple

require 'socket' #Obtenir la bibliothèque standard socket server = TCPServer.open(2000) #La socket écoute sur le port 2000 loop { #Exécuter le service indéfiniment Thread.start(server.accept) do |client| client.puts(Time.now.ctime) #Envoyer l'heure au client client.puts "Fermeture de la connexion. Au revoir !" client.close #Fermer la connexion client end }

Dans cet exemple, la socket s'exécute indéfiniment. Lorsque server.accept reçoit une connexion client, un nouveau thread est créé et commence immédiatement à traiter la requête. Le programme principal revient ensuite immédiatement en boucle et attend de nouvelles connexions.


Mini navigateur Web

Nous pouvons utiliser la bibliothèque socket pour implémenter n'importe quel protocole Internet. Le code suivant montre comment récupérer le contenu d'une page web :

Exemple

require 'socket' host = 'www.w3cschool.cc' #Serveur Web port = 80 #Port HTTP par défaut path = "/index.htm" #Chemin du fichier à récupérer #Ceci est une requête HTTP request = "GET #{path} HTTP/1.0\r\n\r\n" socket = TCPSocket.open(host,port) #Se connecter au serveur socket.print(request) #Envoyer la requête response = socket.read #Lire la réponse complète # Diviser la réponse à la première ligne vide en en-têtes et corps headers,body = response.split("\r\n\r\n", 2) print body #Afficher le résultat

Pour implémenter un client de type web, vous pouvez utiliser des bibliothèques HTTP préconstruites telles que Net::HTTP.

Le code suivant est équivalent au code précédent :

Exemple

require 'net/http' #La bibliothèque dont nous avons besoin host = 'www.w3cschool.cc' #Serveur Web path = '/index.htm' #Le fichier que nous voulons http = Net::HTTP.new(host) #Créer une connexion headers, body = http.get(path) #Demander le fichier if headers.code == "200" #Vérifier le code d'état print body else puts "#{headers.code} #{headers.message}" end

Ci-dessus, nous n'avons présenté que brièvement l'application des sockets en Ruby. Pour plus de documentation, veuillez consulter :Bibliothèque Socket de Ruby et méthodes de classe

Autres extensions