Ruby-Socket-Programmierung

Ruby bietet zwei Zugriffsebenen auf Netzwerkdienste. Auf der niedrigen Ebene können Sie auf das Betriebssystem zugreifen, wodurch Sie grundlegende Socket-Unterstützung für Clients und Server für verbindungsorientierte und verbindungslose Protokolle implementieren können.

Ruby bietet einheitliche Unterstützung für Anwendungsnetzwerkprotokolle wie FTP, HTTP usw.

Ob auf hoher oder niedriger Ebene, Ruby bietet einige grundlegende Klassen, mit denen Sie mit vielen Protokollen wie TCP, UDP, SOCKS interagieren können, ohne an die Netzwerkschicht gebunden zu sein. Diese Klassen bieten auch Hilfsklassen, mit denen Sie einfach von Servern lesen und in sie schreiben können.

Als Nächstes lernen wir, wie man Ruby-Socket-Programmierung durchführt.


Was sind Sockets

Wenn die Anwendungsschicht zur Datenkommunikation mit der Transportschicht kommuniziert, tritt bei TCP und UDP das Problem auf, gleichzeitig nebenläufige Dienste für mehrere Anwendungsprozesse bereitzustellen. Mehrere TCP-Verbindungen oder mehrere Anwendungsprozesse müssen möglicherweise Daten über denselben TCP-Protokollport übertragen. Um verschiedene Anwendungsprozesse und Verbindungen zu unterscheiden, stellen viele Computerbetriebssysteme eine Schnittstelle namens Socket bereit, über die Anwendungen mit TCP/IP-Protokollen interagieren und Netzwerkkommunikation sowie Verbindungen zwischen verschiedenen Anwendungsprozessen unterscheiden können.

Das Erstellen eines Sockets umfasst hauptsächlich drei Parameter: die Ziel-IP-Adresse für die Kommunikation, das verwendete Transportschichtprotokoll (TCP oder UDP) und die verwendete Portnummer. Die ursprüngliche Bedeutung von Socket ist "socket". Durch Kombination dieser drei Parameter und deren Bindung an einen "socket" kann die Anwendungsschicht die Socket-Schnittstelle zur Transportschicht nutzen, um die Kommunikation verschiedener Anwendungsprozesse oder Netzwerkverbindungen zu unterscheiden und nebenläufige Datenübertragungsdienste zu ermöglichen.

Socket-Begriffe:

OptionBeschreibung
domainGibt die verwendete Protokollfamilie an, normalerweise PF_INET, PF_UNIX, PF_X25 usw.
typeGibt den Sockettyp an: SOCK_STREAM oder SOCK_DGRAM. Die Socket-Schnittstelle definiert außerdem Raw-Sockets (SOCK_RAW), wodurch Programme Protokolle auf niedrigerer Ebene verwenden können.
protocolÜblicherweise wird 0 zugewiesen.
hostnameBezeichner der Netzwerkschnittstelle:
  • String, kann ein Hostname oder eine IP-Adresse sein
  • String "<broadcast>", gibt die INADDR_BROADCAST-Adresse an.
  • Zeichenkette der Länge null, gibt INADDR_ANY an
  • Eine Ganzzahl, interpretiert als Binäradresse in Host-Byte-Reihenfolge.
portport ist die Nummer des Ports. Jeder Server lauscht auf einer oder mehreren Portnummern für Clientverbindungen. Eine Portnummer kann eine Fixnum-Portnummer oder eine Zeichenkette sein, die den Servernamen und Port enthält.

Einfacher Client

Unten haben wir ein einfaches Client-Beispiel unter Verwendung eines gegebenen Hosts und Ports geschrieben. Die Ruby-Klasse TCPSocket stellt die Methode open zum Öffnen eines Sockets bereit.

TCPSocket.open(hosname, port) öffnet eine TCP-Verbindung.

Sobald Sie eine Socket-Verbindung geöffnet haben, können Sie daraus wie aus einem IO-Objekt lesen. Wenn Sie fertig sind, müssen Sie die Verbindung schließen, wie beim Schließen einer Datei.

Das folgende Beispiel zeigt, wie man sich mit einem angegebenen Host verbindet, Daten aus dem Socket liest und schließlich den Socket schließt:

Beispiel

require 'socket' #Sockets ist die Standardbibliothek hostname = 'localhost' port = 2000 s = TCPSocket.open(hostname, port) while line = s.gets #Liest jede Datenzeile aus dem Socket puts line.chop #Auf Terminal ausgeben end s.close #Socket schließen

Einfacher Server

In Ruby können Sie die TCPServer-Klasse verwenden, um einen einfachen Dienst zu schreiben. Ein TCPServer-Objekt ist ein Factory-Objekt für TCPSocket.

Jetzt verwenden wir TCPServer.open(hostname, port), um ein TCPServer-Objekt zu erstellen.

Als Nächstes rufen Sie die accept-Methode von TCPServer auf. Diese Methode wartet, bis sich ein Client mit dem angegebenen Port verbindet, und gibt dann ein TCPSocket-Objekt zurück, das die Verbindung zu diesem Client darstellt.

Beispiel

require 'socket' #Socket-Standardbibliothek einbinden server = TCPServer.open(2000) #Socket lauscht auf Port 2000 loop { #Dienst endlos ausführen client = server.accept #Auf Client-Verbindung warten client.puts(Time.now.ctime) #Zeit an den Client senden client.puts "Verbindung wird geschlossen. Tschüss!" client.close #Client-Verbindung schließen }

Führe nun den obigen Code auf dem Server aus und sieh dir die Wirkung an.


Multi-Client-TCP-Dienst

Im Internet haben die meisten Dienste eine große Anzahl von Client-Verbindungen.

Mit Rubys Thread-Klasse lassen sich leicht Multithread-Dienste erstellen. Ein Thread verarbeitet Client-Verbindungen, während der Hauptthread auf weitere Verbindungen wartet.

Beispiel

require 'socket' #Socket-Standardbibliothek einbinden server = TCPServer.open(2000) #Socket lauscht auf Port 2000 loop { #Dienst dauerhaft ausführen Thread.start(server.accept) do |client| client.puts(Time.now.ctime) #Zeit an Client senden client.puts "Verbindung wird geschlossen. Tschüss!" client.close #Client-Verbindung schließen end }

In diesem Beispiel läuft der Socket dauerhaft. Wenn server.accept eine Client-Verbindung empfängt, wird ein neuer Thread erstellt, der sofort mit der Verarbeitung der Anfrage beginnt. Das Hauptprogramm kehrt dann sofort in die Schleife zurück und wartet auf neue Verbindungen.


Kleiner Webbrowser

Wir können die Socket-Bibliothek verwenden, um jedes Internetprotokoll zu implementieren. Der folgende Code zeigt, wie man den Inhalt einer Webseite abruft:

Beispiel

require 'socket' host = 'www.w3cschool.cc' #Webserver port = 80 #Standard-HTTP-Port path = "/index.htm" #Pfad der abzurufenden Datei #Dies ist eine HTTP-Anfrage request = "GET #{path} HTTP/1.0\r\n\r\n" socket = TCPSocket.open(host,port) #Verbindung zum Server herstellen socket.print(request) #Anfrage senden response = socket.read #Die vollständige Antwort lesen # Antwort an der ersten Leerzeile in Header und Body aufteilen headers,body = response.split("\r\n\r\n", 2) print body #Ergebnis ausgeben

Um einen webähnlichen Client zu implementieren, können Sie vorgefertigte Bibliotheken für HTTP wie Net::HTTP verwenden.

Der folgende Code entspricht dem vorherigen Code:

Beispiel

require 'net/http' #Die benötigte Bibliothek host = 'www.w3cschool.cc' #Webserver path = '/index.htm' #Die gewünschte Datei http = Net::HTTP.new(host) #Verbindung herstellen headers, body = http.get(path) #Datei anfordern if headers.code == "200" #Statuscode prüfen print body else puts "#{headers.code} #{headers.message}" end

Oben haben wir nur kurz die Anwendung von Sockets in Ruby vorgestellt. Weitere Dokumentation finden Sie unter:Ruby-Socket-Bibliothek und Klassenmethoden

Weitere Erweiterungen