Ruby - Programmation de socket

Ruby fournit deux niveaux d'accès aux services réseau. À un niveau bas, vous pouvez accéder à la prise en charge de socket de base dans le système d'exploitation sous-jacent, ce qui vous permet d'implémenter des clients et des serveurs pour les protocoles orientés connexion et sans connexion.

Ruby dispose également de bibliothèques qui fournissent un accès de niveau supérieur à des protocoles réseau spécifiques au niveau de l'application, tels que FTP, HTTP, etc.

Ce chapitre vous donne une compréhension du concept le plus connu de la mise en réseau - Programmation de socket.

Que sont les sockets?

Les sockets sont les extrémités d'un canal de communication bidirectionnel. Les sockets peuvent communiquer au sein d'un processus, entre des processus sur la même machine ou entre des processus sur différents continents.

Les sockets peuvent être implémentés sur un certain nombre de types de canaux différents: sockets de domaine Unix, TCP, UDP, etc. Le socket fournit des classes spécifiques pour gérer les transports courants ainsi qu'une interface générique pour gérer le reste.

Les sockets ont leur propre vocabulaire -

N ° Sr. Terme et description
1

domain

La famille de protocoles qui sera utilisée comme mécanisme de transport. Ces valeurs sont des constantes telles que PF_INET, PF_UNIX, PF_X25, etc.

2

type

Type de communication entre les deux points de terminaison, généralement SOCK_STREAM pour les protocoles orientés connexion et SOCK_DGRAM pour les protocoles sans connexion.

3

protocol

Typiquement zéro, cela peut être utilisé pour identifier une variante d'un protocole dans un domaine et un type.

4

hostname

L'identifiant d'une interface réseau -

Une chaîne, qui peut être un nom d'hôte, une adresse à quatre points ou une adresse IPV6 en notation deux-points (et éventuellement un point)

Une chaîne "<broadcast>", qui spécifie une adresse INADDR_BROADCAST.

Une chaîne de longueur nulle, qui spécifie INADDR_ANY, ou

Un entier, interprété comme une adresse binaire dans l'ordre des octets de l'hôte.

5

port

Chaque serveur écoute les clients appelant sur un ou plusieurs ports. Un port peut être un numéro de port Fixnum, une chaîne contenant un numéro de port ou le nom d'un service.

Un client simple

Ici, nous allons écrire un programme client très simple, qui ouvrira une connexion vers un port et un hôte donnés. Classe de rubisTCPSocketfournit une fonction ouverte pour ouvrir une telle prise.

le TCPSocket.open(hosname, port )ouvre une connexion TCP au nom d' hôte sur le port .

Une fois que vous avez une socket ouverte, vous pouvez la lire comme n'importe quel objet IO. Une fois terminé, n'oubliez pas de le fermer, comme vous le feriez pour un fichier.

Le code suivant est un client très simple qui se connecte à un hôte et un port donnés, lit toutes les données disponibles à partir du socket, puis quitte -

require 'socket'        # Sockets are in standard library

hostname = 'localhost'
port = 2000

s = TCPSocket.open(hostname, port)

while line = s.gets     # Read lines from the socket
   puts line.chop       # And print with platform line terminator
end
s.close                 # Close the socket when done

Un serveur simple

Pour écrire des serveurs Internet, nous utilisons le TCPServerclasse. Un objet TCPServer est une fabrique d'objets TCPSocket.

Appelez maintenant TCPServer.open(hostname, portpour spécifier un port pour votre service et créer unTCPServer objet.

Ensuite, appelez la méthode accept de l'objet TCPServer renvoyé. Cette méthode attend jusqu'à ce qu'un client se connecte au port que vous avez spécifié, puis renvoie un objet TCPSocket qui représente la connexion à ce client.

require 'socket'                 # Get sockets from stdlib

server = TCPServer.open(2000)    # Socket to listen on port 2000
loop {                           # Servers run forever
   client = server.accept        # Wait for a client to connect
   client.puts(Time.now.ctime)   # Send the time to the client
   client.puts "Closing the connection. Bye!"
   client.close                  # Disconnect from the client
}

Maintenant, exécutez ce serveur en arrière-plan, puis exécutez le client ci-dessus pour voir le résultat.

Serveurs TCP multi-clients

La plupart des serveurs sur Internet sont conçus pour traiter un grand nombre de clients à la fois.

La classe Thread de Ruby facilite la création d'un serveur multithread.one qui accepte les requêtes et crée immédiatement un nouveau thread d'exécution pour traiter la connexion tout en permettant au programme principal d'attendre plus de connexions -

require 'socket'                 # Get sockets from stdlib

server = TCPServer.open(2000)    # Socket to listen on port 2000
loop {                           # Servers run forever
   Thread.start(server.accept) do |client|
   client.puts(Time.now.ctime)   # Send the time to the client
   client.puts "Closing the connection. Bye!"
   client.close                  # Disconnect from the client
   end
}

Dans cet exemple, vous avez une boucle permanente, et lorsque server.accept répond, un nouveau thread est créé et démarré immédiatement pour gérer la connexion qui vient d'être acceptée, en utilisant l'objet de connexion passé dans le thread. Cependant, le programme principal effectue immédiatement une boucle et attend de nouvelles connexions.

Utiliser les threads Ruby de cette manière signifie que le code est portable et fonctionnera de la même manière sous Linux, OS X et Windows.

Un petit navigateur Web

Nous pouvons utiliser la bibliothèque socket pour implémenter n'importe quel protocole Internet. Voici, par exemple, un code pour récupérer le contenu d'une page Web -

require 'socket'
 
host = 'www.tutorialspoint.com'     # The web server
port = 80                           # Default HTTP port
path = "/index.htm"                 # The file we want 

# This is the HTTP request we send to fetch a file
request = "GET #{path} HTTP/1.0\r\n\r\n"

socket = TCPSocket.open(host,port)  # Connect to server
socket.print(request)               # Send request
response = socket.read              # Read complete response
# Split response at first blank line into headers and body
headers,body = response.split("\r\n\r\n", 2) 
print body                          # And display it

Pour implémenter le client Web similaire, vous pouvez utiliser une bibliothèque prédéfinie comme Net::HTTPpour travailler avec HTTP. Voici le code qui fait l'équivalent du code précédent -

require 'net/http'                  # The library we need
host = 'www.tutorialspoint.com'     # The web server
path = '/index.htm'                 # The file we want 

http = Net::HTTP.new(host)          # Create a connection
headers, body = http.get(path)      # Request the file
if headers.code == "200"            # Check the status code   
   print body                        
else                                
   puts "#{headers.code} #{headers.message}" 
end

Veuillez vérifier que les bibliothèques similaires fonctionnent avec les protocoles FTP, SMTP, POP et IMAP.

Lectures supplémentaires

Nous vous avons donné un démarrage rapide sur la programmation de socket. C'est un gros sujet, il est donc recommandé de passer par Ruby Socket Library et Class Methods pour trouver plus de détails.