Blockiert
Das zweite Problem mit den beiden Serversockets liegt darin, dass der »accept()«
-Aufruf im Normalfall blockiert, während er auf eine Verbindung wartet. Um damit umzugehen, könnte der Entwickler theoretisch zwei Serverprozesse starten oder mit mehreren Threads arbeiten.
Das ist aber gar nicht notwendig, denn das Problem lässt sich viel eleganter mit Select lösen. Damit kann das Programm auf mehrere Sockets gleichzeitig warten. Das mag ein wenig aufwändig erscheinen, doch in der Praxis kommen komplexere Anwendungen ohnehin nicht ohne »select«
oder Alternativen wie »poll«
oder »epoll«
aus. In Python findet man »select()«
im Standardmodul Select [6]:
readable, writable, special = select.select(rlist, wlist, xlist[, timeout])
Die Parameter »rlist«
, »wlist«
und »xlist«
sind Listen von File- oder Socket-Objekten, die auf Lesbarkeit, Schreibbarkeit oder außergewöhnliche Ereignisse reagieren sollen. Die drei Rückgabewerte liefern Listen jener Objekte, bei denen tatsächlich der abgewartete Zustand eingetreten ist. Für ankommende Verbindungen ist dies »readable«
.
In Python ist »accept()«
als Methode des Socketobjekts abgebildet und liefert ein 2-Tupel zurück:
(conn, address) = socket.accept()
Dabei ist »conn«
der neue Socket der aufgebauten Verbindung, »address«
die Adresse der Gegenseite in Pythons Tupel-Notation.
Das nächste Codebeispiel (Listing 6) wendet die besprochenen Techniken praktisch an. Es lauscht auf einem Port, nimmt eingehende Verbindungen an und übermittelt die ankommende IP-Adresse. Abbildung 3 zeigt Telnet-Sitzungen mit dem Server per IPv6 und IPv4.
Listing 6
server.py
01 #!/usr/bin/env python
02 import sys
03 from socket import *
04 from select import select
05
06 host = None
07 port = sys.argv[1]
08 flags = AI_PASSIVE
09
10 serverSockets = []
11
12 for addrinfo in getaddrinfo(host, port, AF_UNSPEC, SOCK_STREAM, 0, flags):
13 family, socktype, proto, canonname, sockaddr = addrinfo
14 serverSocket = socket(family, socktype, proto)
15 if family==AF_INET6:
16 serverSocket.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 1)
17 serverSocket.bind(sockaddr)
18 serverSocket.listen(1)
19 serverSockets.append(serverSocket)
20
21
22 while True:
23 readable, writable, special = select( serverSockets, [], [])
24 for readSocket in readable:
25 connectionSocket, connectionAddress = readSocket.accept()
26 connectionSocket.send("Hello {0}\n".format(connectionAddress).encode("ascii"))
27 connectionSocket.close()
Das Qt-Toolkit
Das objektorientierte C++-Framework Qt bietet in der »QtNetwork«
-Bibliothek [7] einige Abstraktionen zur Netzwerk-Programmierung an. Im Normalfall funktionieren Clientprogramme, welche die richtigen Methoden verwenden, automatisch mit IPv6. Zur Netzwerk-Programmierung stellt Qt die Klassen »QTcpSocket«
und »QUdpSocket«
bereit, die beide von der Basisklasse »QAbstractSocket«
abgeleitet sind.
Um in einem Clientprogramm eine TCP-Verbindung herzustellen, erzeugt der Entwickler zunächst einen »QTcpSocket«
und ruft die in der Basisklasse »QAbstractSocket«
definierte Methode »connectToHost()«
auf (Listing 7). Diese übernimmt die Namensauflösung, was im Normalfall unter der Decke mit »getaddrinfo()«
geschieht.
Listing 7
connectToHost
01 void connectToHost ( const QString & hostName, quint16 port, OpenMode openMode = ReadWrite )
Als kleines Beispiel dient ein minimales Qt-Programm (Listing 8), das eine Verbindung zu jenem Webserver herzustellen versucht, dessen Namen ihm der Anwender als ersten Kommandozeilen-Parameter übergibt. Als Antwort erhält der Benutzer die IP-Adresse (Abbildung 4).
Listing 8
simpleClient.cpp
01 #include <QtCore/QCoreApplication>
02 #include <QtCore/QStringList>
03 #include <QtNetwork/QHostAddress>
04 #include <QtNetwork/QTcpSocket>
05
06 #include <iostream>
07
08 int main(int argc, char *argv[])
09 {
10 QCoreApplication app(argc, argv);
11
12 QString host = app.arguments().at(1);
13 int port = 80;
14
15 QTcpSocket socket;
16 socket.connectToHost(host, port);
17
18 if (!socket.waitForConnected(1000)) {
19 std::cout << "Could not connect" << std::endl;
20 return 10;
21 }
22
23 QHostAddress peerAddress = socket.peerAddress();
24 QString address = peerAddress.toString();
25 std::cout << "Connected to "
26 << address.toAscii().constData() << std::endl;
27 socket.close();
28 return 0;
29 }
Für die Ausgabe kommt »QHostAddress«
zum Einsatz [8]: Dies ist Qts Abstraktion von IPv4- und IPv6-Adressen, sie bietet unter anderem die Methode »QHostAddress::toString()«
an.
Die »QCoreApplication«
ermöglicht es, ein Qt-Programm ohne GUI zu erstellen (Listing 8, Zeile 10). Nach dem »connectToHost()«
(Zeile 16), das sofort zurückkehrt, ruft der Code »waitForConnected()«
auf, um auf die Verbindung zu warten (Zeile 18). Alternativ ist es möglich, das Signal »connected()«
zu einem geeigneten Slot zu verbinden. Ist eine Verbindung erfolgt, gibt das Programm die »peerAddress«
aus.
In einer Umgebung mit funktionierender IPv6-Unterstützung zeigt sich, dass das Programm tatsächlich ganz automatisch eine IPv6-Verbindung aufnimmt:
$ ./simpleClient www.google.com Connected to 2A00:1450:4001:C01:0:0:0:68%0
Das ist praktisch, bietet aber beileibe nicht die Einflussmöglichkeiten, die »getaddrinfo()«
dem C-Programmierer einräumt. Dem am nächsten kommt »QHostInfo«
[9], das Methoden zur Namensauflösung bereitstellt. Leider sind über »QHostInfo«
aber nicht alle Annehmlichkeiten von »getaddrinfo()«
zugänglich: Es ist nicht möglich vorzugeben, ob man IPv4- oder IPv6-Adressen haben will, und der Entwickler kann keine Flags wie etwa »AI_ADDRCONFIG«
angeben.
Die Anwendung ist einfach: Die statische Methode »QHostInfo::fromName(const QString& name)«
liefert eine »QHostInfo«
-Instanz zurück. Diese gibt über »QHostInfo::addresses()«
eine »QList«
von »QHostAddress-Instanzen«
zurück. Es existiert auch eine nebenläufige Variante namens »lookupHost()«
, welche die notwendigen Anfragen in separaten Threads erledigt und dann den angegebenen Slot des Objekts aufruft.
Diesen Artikel als PDF kaufen
Express-Kauf als PDF
Umfang: 7 Heftseiten
Preis € 0,99
(inkl. 19% MwSt.)
Als digitales Abo
Weitere Produkte im Medialinx Shop »
Versandartikel
Onlineartikel
Alle Rezensionen aus dem Linux-Magazin
- Buecher/07 Bücher über 3-D-Programmierung sowie die Sprache Dart
- Buecher/06 Bücher über Map-Reduce und über die Sprache Erlang
- Buecher/05 Bücher über Scala und über Suchmaschinen-Optimierung
- Buecher/04 Bücher über Metasploit sowie über Erlang/OTP
- Buecher/03 Bücher über die LPI-Level-2-Zertifizierung
- Buecher/02 Bücher über Node.js und über nebenläufige Programmierung
- Buecher/01 Bücher über Linux-HA sowie über PHP-Webprogrammierung
- Buecher/12 Bücher über HTML-5-Apps sowie Computer Vision mit Python
- Buecher/11 Bücher über Statistik sowie über C++-Metaprogrammierung
- Buecher/10 Bücher zu PHP-Webbots sowie zur Emacs-Programmierung
Insecurity Bulletin
Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...





