34.5 Telnet – telnetlib
Das Modul telnetlib ermöglicht die Verwendung des sogenannten Telnet-Netzwerkprotokolls (Teletype Network). Telnet wurde als möglichst einfaches bidirektionales Netzwerkprotokoll konzipiert. Häufig wird Telnet dazu verwendet, einen kommandozeilenbasierenden Zugriff auf einen entfernten Rechner zu ermöglichen. Der Vorteil des Telnet-Protokolls liegt in seiner Einfachheit, so ist keine große Infrastruktur notwendig, um es einzusetzen. Auf der anderen Seite bietet es aber keine Möglichkeit zur Verschlüsselung der übertragenen Daten und wurde deshalb nach und nach von anderen, in diesem Bereich stärkeren Protokollen wie beispielsweise SSH verdrängt.
34.5.1 Die Klasse Telnet
Das Modul telnetlib enthält im Wesentlichen die Klasse Telnet, über die die weitere Kommunikation mit dem entfernten Rechner abläuft. Der Konstruktor der Klasse Telnet hat die im Folgenden beschriebene Schnittstelle.
Telnet([host, port, timeout])
Hiermit wird eine Instanz der Klasse Telnet erzeugt. Optional übergeben Sie bereits hier den Hostnamen und den Port des Rechners, zu dem eine Verbindung hergestellt werden soll. Wenn keiner der Parameter angegeben wird, muss die erzeugte Telnet-Instanz explizit durch Aufruf der Methode open verbunden werden. Die Angabe einer Portnummer ist nur dann notwendig, wenn die Verbindung nicht über den Standardport 23 ablaufen soll.
Über den optionalen Parameter timeout lässt sich ein Timeout-Wert in Sekunden angeben, der beim Verbindungsversuch zum Server eingehalten werden soll. Wenn timeout nicht angegeben wurde, wird ein Standardwert als Timeout verwendet.
Die Verbindung zu einem Server kann auch nach der Instanziierung von Telnet über die Methode open erfolgen. Diese Methode hat die gleiche Schnittstelle wie der Konstruktor. Eine bestehende Verbindung lässt sich über einen Aufruf der parameterlosen Methode close beenden.
Nachdem sie erzeugt und mit dem Zielrechner verbunden wurde, kann eine Telnet-Instanz zur Kommunikation mit dem verbundenen Rechner verwendet werden. Dazu enthält sie eine Reihe Methoden, von denen die wichtigsten im Folgenden erläutert werden.
[»] Hinweis
Die Telnet-Klasse ist seit Python 3.6 ein Kontextmanager und lässt sich mit der with-Anweisung verwenden:
with telnetlib.Telnet(host, port) as t:
pass
read_until(expected, [timeout])
Diese Methode liest ankommende Daten, bis der String expected empfangen wurde. Alternativ geben Sie einen Timeout in Sekunden als zweiten Parameter an, nach dessen Ablauf der Lesevorgang abgebrochen wird. Die gelesenen Daten werden als bytes-String zurückgegeben.
read_all()
Diese Methode liest alle ankommenden Daten, bis die Verbindung geschlossen wird. Beachten Sie, dass diese Methode das Programm auch so lange blockiert. Die gelesenen Daten werden als bytes-String zurückgegeben.
write(buffer)
Diese Methode sendet den String buffer zum Verbindungspartner. Diese Funktion kann das Programm blockieren, wenn die Daten nicht sofort geschrieben werden können.
34.5.2 Beispiel
Im folgenden Beispielprogramm wird das Modul telnetlib dazu verwendet, zu einem POP3-Server zu verbinden. Dabei möchten wir auf die abstrahierte Schnittstelle des Moduls poplib verzichten und dem Server direkt POP3-Kommandos senden. Da das POP3-Protokoll jedoch relativ simpel ist und auf lesbaren Kommandos basiert, stellt dies kein großes Problem dar.
Das Ziel des Programms ist es, die Ausgabe des POP3-Kommandos LIST zu erhalten, das die Indizes aller im Posteingang liegenden Mails auflistet.
Im Programm soll die Telnet-Kommunikation möglichst komfortabel über eine auf POP3 zugeschnittene Klasse ablaufen:
import telnetlib
class POP3Telnet:
def __init__(self, host, port):
self.tel = telnetlib.Telnet(host, port)
self.lese_daten()
def close(self):
self.tel.close()
def lese_daten(self):
return self.tel.read_until(b".\r\n", 20.0)
def kommando(self, kom):
self.tel.write(("{}\r\n".format(kom)).encode())
return self.lese_daten()
Dem Konstruktor der Klasse POP3Telnet werden Hostname und Port des POP3-Servers übergeben. Intern wird dann eine Instanz der Klasse Telnet erzeugt und mit diesem Server verbunden. Durch Aufruf der Methode lese_daten wird die Begrüßungsnachricht des Servers ausgelesen und verworfen, da sie nicht weiter von Interesse ist, aber bei späteren Lesevorgängen stören würde.
Wichtig sind die Methoden lese_daten und kommando. Die Methode lese_daten liest genau einen Antwort-String des POP3-Servers ein. Eine solche Antwort wird stets durch den String ".\r\n" beendet. Der gelesene String wird zurückgegeben. Damit dieser Lesevorgang das Programm bei einem unerreichbaren Server nicht auf unbestimmte Zeit blockiert, wurde ein Timeout von 20 Sekunden festgelegt.
Die zweite wichtige Methode ist kommando. Sie erlaubt es, einen POP3-Befehl an den Server zu senden. Dieser Befehl wird inklusive eines abschließenden "\r\n" in die Telnet-Instanz geschrieben und von dieser an den verbundenen Rechner weitergeleitet. Schließlich wird die Antwort des Servers eingelesen und zurückgegeben.
Doch die Klasse ist nur der erste Teil des Beispielprogramms. Im nun folgenden zweiten Teil setzen wir die Klasse POP3Telnet zur Kommunikation mit einem POP3-Server ein. Dazu legen wir zunächst die Zugangsdaten für den POP3-Server fest:
host = "pop.server.de"
port = 110
user = "benutzername"
passwd = "passwort"
Jetzt erzeugen wir eine Instanz der Klasse POP3Telnet, die mit dem angegebenen POP3-Server verbunden ist. Dann führen wir die Anmeldeprozedur durch Senden der Kommandos USER und PASS durch.
pop = POP3Telnet(host, port)
pop.kommando("USER {}".format(user))
pop.kommando("PASS {}".format(passwd))
Wenn bei der Anmeldung alles gut gelaufen ist, sind wir an dieser Stelle in der Lage, mit beliebigen POP3-Kommandos auf den Posteingang zuzugreifen. Dann schicken wir das eingangs erwähnte LIST-Kommando. Das LIST-Kommando des POP3-Protokolls liefert eine Liste aller im Posteingang enthaltenen E‐Mails. Jeder Eintrag besteht dabei aus dem ganzzahligen Index der jeweiligen E‐Mail und ihrer Größe in Byte.
Der Server sendet auf LIST zwei Antwort-Strings. Von diesen interessiert uns nur der zweite, da dieser die Daten über vorhandene E‐Mails enthält. Aus diesem Grund müssen wir nach dem Aufruf der Methode kommando noch einmal den zweiten Antwort-String einlesen. Der zurückgegebene String wird ausgegeben. Im Code sieht das folgendermaßen aus:
pop.kommando("LIST")
print(pop.lese_daten().decode())
pop.kommando("QUIT")
pop.close()
Zum Schluss schicken wir das Kommando QUIT an den Server und schließen die Telnet-Verbindung. Die Ausgabe des Beispielprogramms könnte folgendermaßen aussehen:
1 623
2 614
3 1387
.
In diesem Fall befinden sich drei E‐Mails mit den Größen 623, 614 und 1387 Byte im Posteingang.