Ruby - Programmazione socket

Ruby fornisce due livelli di accesso ai servizi di rete. A un livello basso, è possibile accedere al supporto socket di base nel sistema operativo sottostante, che consente di implementare client e server per protocolli orientati alla connessione e senza connessione.

Ruby dispone anche di librerie che forniscono un accesso di livello superiore a specifici protocolli di rete a livello di applicazione, come FTP, HTTP e così via.

Questo capitolo fornisce una comprensione dei concetti più famosi in Networking - Socket Programming.

Cosa sono i socket?

I socket sono gli endpoint di un canale di comunicazione bidirezionale. I socket possono comunicare all'interno di un processo, tra processi sulla stessa macchina o tra processi su continenti diversi.

I socket possono essere implementati su diversi tipi di canali: socket di dominio Unix, TCP, UDP e così via. Il socket fornisce classi specifiche per la gestione dei trasporti comuni, nonché un'interfaccia generica per la gestione del resto.

Le prese hanno il loro vocabolario -

Sr.No. Termine e descrizione
1

domain

La famiglia di protocolli che verrà utilizzata come meccanismo di trasporto. Questi valori sono costanti come PF_INET, PF_UNIX, PF_X25 e così via.

2

type

Il tipo di comunicazioni tra i due endpoint, in genere SOCK_STREAM per i protocolli orientati alla connessione e SOCK_DGRAM per i protocolli senza connessione.

3

protocol

Tipicamente zero, può essere utilizzato per identificare una variante di un protocollo all'interno di un dominio e tipo.

4

hostname

L'identificatore di un'interfaccia di rete -

Una stringa, che può essere un nome host, un indirizzo a quattro punti o un indirizzo IPV6 in notazione con due punti (e possibilmente punto)

Una stringa "<broadcast>", che specifica un indirizzo INADDR_BROADCAST.

Una stringa di lunghezza zero, che specifica INADDR_ANY o

Un numero intero, interpretato come un indirizzo binario nell'ordine dei byte dell'host.

5

port

Ogni server ascolta i client che chiamano su una o più porte. Una porta può essere un numero di porta Fixnum, una stringa contenente un numero di porta o il nome di un servizio.

Un cliente semplice

Qui scriveremo un programma client molto semplice, che aprirà una connessione a una data porta e un determinato host. Classe RubyTCPSocketfornisce la funzione open per aprire tale socket.

Il TCPSocket.open(hosname, port )apre una connessione TCP al nome host sulla porta .

Una volta aperto un socket, puoi leggere da esso come qualsiasi oggetto IO. Quando hai finito, ricordati di chiuderlo, come faresti per chiudere un file.

Il codice seguente è un client molto semplice che si connette a un determinato host e porta, legge tutti i dati disponibili dal socket e quindi esce:

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 semplice server

Per scrivere server Internet, utilizziamo il TCPServerclasse. Un oggetto TCPServer è una factory per oggetti TCPSocket.

Adesso chiama TCPServer.open(hostname, portfunzione per specificare una porta per il servizio e creare un fileTCPServer oggetto.

Avanti, chiamare il accettano metodo dell'oggetto TCPServer restituito. Questo metodo attende che un client si connetta alla porta specificata, quindi restituisce un oggetto TCPSocket che rappresenta la connessione a quel 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
}

Ora, esegui questo server in background e quindi esegui il client sopra per vedere il risultato.

Server TCP multi-client

La maggior parte dei server su Internet è progettata per gestire un gran numero di client contemporaneamente.

La classe Thread di Ruby semplifica la creazione di un server multithread. Uno che accetta le richieste e crea immediatamente un nuovo thread di esecuzione per elaborare la connessione consentendo al programma principale di attendere più connessioni -

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
}

In questo esempio, hai un ciclo permanente e quando server.accept risponde, viene creato e avviato immediatamente un nuovo thread per gestire la connessione che è stata appena accettata, utilizzando l'oggetto connessione passato nel thread. Tuttavia, il programma principale torna immediatamente indietro e attende nuove connessioni.

Usare i thread Ruby in questo modo significa che il codice è portabile e verrà eseguito allo stesso modo su Linux, OS X e Windows.

Un minuscolo browser web

Possiamo usare la libreria socket per implementare qualsiasi protocollo Internet. Ecco, ad esempio, un codice per recuperare il contenuto di una pagina 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

Per implementare il client Web simile, è possibile utilizzare una libreria predefinita come Net::HTTPper lavorare con HTTP. Ecco il codice che fa l'equivalente del codice precedente -

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

Verificare che librerie simili funzionino con i protocolli FTP, SMTP, POP e IMAP.

Ulteriori letture

Ti abbiamo dato un rapido avvio sulla programmazione Socket. È un argomento importante, quindi si consiglia di consultare Ruby Socket Library e Class Methods per trovare maggiori dettagli.