In diesem Kapitel werden Ihnen drei Projekte vorgestellt, welche die Klasse UDPSocket verwenden.
Für das zweite Projekt wird der Quelltext im Kapitel vollständig angegeben. Alle drei Projekt-Archive finden Sie im Downloadbereich.
Unter https://wiki.pythonde.pysv.org/UDP-Broadcasts finden Sie im Text
„UDP-Broadcasts können verwendet werden, damit sich Client und Server in einem Subnetz finden, ohne zunächst zu wissen, auf welchen Hosts sie laufen. Der Server öffnet dazu einen Socket, der auf einem bestimmten Port lauscht. Ein Client kann dann einen UDP-Broadcast auf diesen Port an alle Hosts im Subnetz schicken, worauf der Server antworten kann.“
einen guten Hinweis, wie Sie einen Rundruf im Subnetz realisieren:
[1] Public Sub btnBroadcast_Click() [2] [3] Dim sMessage As String [4] [5] txaShowQuote.Clear() [6] [7] '-- Es wird ein UDP-Socket erzeugt [8] UDPClientSocket = New UDPSocket As "UDPClientSocket" [9] [10] If UDPClientSocket.Status <= Net.Inactive Then [11] UDPClientSocket.Broadcast = True [12] UDPClientSocket.Port = 0 ' Standard-Port für einen UDP-Client [13] UDPClientSocket.Bind() [14] '-- Standard-Subnetz-Maske im Klasse-C-Netz => 255.255.255.0 [15] txbTargetHost.Text = sNetzAdresse & ".255" ' IPv4-Broadcast-IP-Adresse [16] '-- Ziel-Adressierung: Host und Port [17] UDPClientSocket.TargetHost = txbTargetHost.Text [18] UDPClientSocket.TargetPort = txbPort.Text [19] [20] Inc Application.Busy [21] '-- Ein Datagramm wird an das adressierte Ziel (Server) gesendet [22] Write #UDPClientSocket, "broadcast", Len("broadcast") [23] Dec Application.Busy [24] UDPClientSocket.Broadcast = False [25] Endif [26] [27] bBroadcasted = True [28] [29] Wait 0.5 [30] If Not txaShowQuote.Text Then [31] sMessage = "\n\nDer Rundruf wurde von keinem UDP-Socket auf Port " [32] sMessage &= txbPort.Text & "\nim lokalen Netzwerk mit der Netzadresse " [33] sMessage &= sNetzAdresse & " quittiert!" "" [34] LogMessage(sMessage) [35] btnClose.SetFocus() [36] Endif [37] [38] End
Kommentar:
Abbildungen 24.1.3.1.1: Kommunikation UDPServer ↔ UDPClient
Nach dem quittierten Rundruf kennt der Client einen aktiven Server auf 192.168.2.103 mit dem Port 32340. Ferner ist erkennbar, dass der Client auf der gleichen IP-Adresse, aber unter dem vom System zugewiesenen Port 56644 mit dem Server kommuniziert.
Um den Zitat-Dienst des Servers zu nutzen und nicht nur eine Mitteilung zu erhalten, dass der angeforderte Service gegenwärtig nicht erreichbar ist, sollten Sie die (deutsche) Sammlung von Zitaten für den Server installieren:
sudo apt install fortune-mod ' Programm sudo apt-get install fortunes-de ' Zitat-Sammlung
Abbildung 24.1.3.1.2: Server-Client-Programm
Es folgt eine Testbeschreibung für einen Client und zwei Server:
Im zweiten Projekt nutzt ein Client den Zeit-Service eines Zeit-Servers auf dem reservierten Port 123. Dazu schickt der Client ein leeres Datagramm zum Server. Dieser quittiert den Empfang des leeren Datagramms mit dem Senden eines Datagramms, dessen Inhalt die aktuelle Zeit enthält:
Abbildung 24.1.3.1.3: Client auf Port 123
Der Quelltext für den Client wird vollständig angegeben:
[1] ' Gambas class file [2] [3] Public UDPClient As UdpSocket [4] [5] Public Sub Form_Open() [6] UDPClient = New UdpSocket As "UDPClient" [7] '-- Initialisierung des UDP-Sockets [8] UDPClient.Port = 0 [9] UDPClient.Bind() [10] '-- Vollständige Adressierung: [11] '-- TimeServerURL: ptbtime1.ptb.de -> IP: 192.53.103.108 [12] UDPClient.TargetHost = "192.53.103.108" [13] '-- Für NTP ist der UDP-Port 123 reserviert. [14] UDPClient.Targetport = 123 [15] FMain.Caption = "Datagramm vom NTP-Server `ptbtime1.ptb.de` (Port 123)" [16] End [17] [18] Public Sub UDPClient_Read() [19] [20] Dim sData As String [21] Dim i, iVSeconds As Integer [22] Dim VSeconds As Long [23] Dim CurrentDate As Date [24] [25] '-- Auslesen des Zeit-Datagramms vom NTP-Server - gespeichert in `sData` [26] Read #UDPClient, sData, Lof(UDPClient) [27] '-- Auswerten des Zeit-Datagramms -> https://de.wikipedia.org/wiki/Network_Time_Protocol [28] For i = 17 To 20 [29] VSeconds += Asc(Mid$(sData, 37 - i, 1)) * 256 ^ (i - 17) [30] Next [31] iVSeconds = VSeconds - 2208988800 ' - System.TimeZone [32] CurrentDate = DateAdd("01/01/1970", gb.second, iVSeconds) [33] '-- Formatieren des aktuellen Zeitstempels [34] lblDateTime.Text = Format(CurrentDate, "dd.mm.yyyy hh:nn:ss") [35] End [36] [37] Public Sub UDPClient_Error() [38] [39] Select Case UDPClient.Status [40] Case Net.CannotBindSocket [41] Message.Error(("Unable to Bind to that port")) [42] Case Net.CannotCreateSocket [43] Message.Error(("System does not allow to create a socket")) [44] Case Net.CannotRead [45] Message.Error(("Error Sending Data")) [46] Case Net.CannotWrite [47] Message.Error(("Error Receiving Data")) [48] End Select [49] End [50] [51] Public Sub btnGetTime_Click() [52] '-- Der NTP-Server reagiert auf den Empfang eines leeren Datagramms mit [53] '-- dem Senden eines Datagramms, dessen Inhalt den aktuellen Zeitstempel enthält. [54] [55] '-- Abschicken eines leeren Datagramms an den NTP-Server -> ' # + 47 mal Nul (=> Chr(0)) [56] Write #UDPClient, Chr$(35) & String$(47, Chr$(0)), 48 [57] End [58] [59] Public Sub Form_Close() [60] If UDPClient Then [61] If UDPClient.Status > 0 Then UDPClient.Close() [62] Endif [63] End
Das dritte Projekt basiert auf einem Projekt aus dem Quelltext von Gambas, das den Einsatz der Klasse UDPSocket demonstriert. Der Service besteht darin, dass eine von einem Client gesendete Zeichenkette vom Server als reverse Zeichenkette an den Client zurück geschickt wird, der den Dienst angefordert hat:
Abbildung 24.1.3.1.4: Projekt 3
Beachten Sie die unterschiedlichen Port-Nummern von Client A und von Client B im mittleren Bild, mit denen die Kommunikation mit dem Server realisiert wird!