User Tools

Site Tools


Sidebar

Network and communication

k24:k24.1:k24.1.2:k24.1.2.1:start

24.1.2.1 Digression - Sockets

The network aspects described in this chapter relate to localhost and sockets. An attempt is made to show how socket theory is represented in properties, methods and events of the Gambas classes Socket and Server-Socket and how these classes are used in server as well as client programs.

This digression is intended to promote a basic understanding of the use of sockets as an interface for programming network applications with Gambas.

24.1.2.1.1 Localhost

Localhost is not only the name for the virtual server representing it on a machine, but also its domain name. Localhost has the IPv4 address 127.0.0.1 permanently assigned by ICANN, which points to the server on its own computer. The corresponding IPv6 address is reserved with ::1.

At https://www.de.paessler.com/it-explained/ip-address you will find a short description on the subject of IP addresses as well as other interesting aspects at these websites:

If you try to call the domain in a browser with http://127.0.0.1 or http://localhost, a loopback is triggered. The request is not forwarded to the Internet via the router. In order for the reference to one's own computer to work, the so-called loopback device is created by the operating system. With the command ifconfig in a console you get essential information about the corresponding virtual network interface lo:

hans@mint-183 ~ $ ifconfig
lo        Link encap:Lokale Schleife
          inet Adresse:127.0.0.1  Maske:255.0.0.0
          inet6-Adresse: ::1/128 Gültigkeitsbereich:Maschine
          UP LOOPBACK RUNNING  MTU:65536  Metrik:1
          RX-Pakete:3716 Fehler:0 Verloren:0 Überläufe:0 Fenster:0
          TX-Pakete:3716 Fehler:0 Verloren:0 Überläufe:0 Träger:0
          Kollisionen:0 Sendewarteschlangenlänge:1000
          RX-Bytes:1393737 (1.3 MB)  TX-Bytes:1393737 (1.3 MB)

With the ping command - here with three pings - you can determine whether and with what runtimes the localhost on your computer can be reached:

hans@mint-183 ~ $ ping localhost -c 3
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.026 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.038 ms
--- localhost ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2032ms
rtt min/avg/max/mdev = 0.026/0.034/0.038/0.005 ms

The possibility of always addressing the local computer as 'localhost' in network applications makes it possible to establish a TCP connection even without knowing the host name of the computer or the exact IP address.

The virtual network interface responds to every local IPv4 address in the address range 127.0.0.1/8. It then redirects a connection from 127.0.0.1 to 127.255.255.254 or the domain localhost to itself. If an IP address begins with the block 127. from the range 127.0.0.1 to 127.255.255.254, these IP addresses are identified with the domain name localhost and set to 127.0.0.1! Any IP address beginning with 127. is considered a loopback address.

24.1.2.1.2 Socket

In the first part, a conceptual overview of socket programming for TCP/IP server-client applications is given. Only in the second part will details of Gambas programming be dealt with.

Sockets offer an elementary interface for programming network applications, because they provide functions for establishing network connections and for communication between applications in networks.

  • Sockets are network connection endpoints.
  • Sockets are supported by all common operating systems.
  • Sockets encapsulate the details of network communication.
  • Sockets support connection-oriented and connectionless network communication.
  • Sockets rely on protocols such as TCP or UDP. Data is exchanged via either streams (TCP) or datagrams (UDP).
  • Sockets always require a complete address for network communication, consisting of IP address and port number (port).
  • The creation and configuration of a (server) socket is independent of the service that a server offers.

The socket interface offers a network application the possibility to establish the connection between client and server via TCP (stream socket), UDP (datagram socket) or directly via a file (Unix socket).

Network applications are designed as server-client applications, where a server offers a service that can be used by many clients. For this reason, there are (simple) sockets and server sockets in Gambas.

  • If you want to use a service, you need to know both the IP address of the server and the port! The IP address and the port are fixed values.
  • Different services running on a server in the same subnet and therefore under the same IP address are identified by their (different) port number!
  • A client, on the other hand, does not need a fixed port at start-up! It dynamically requests the next available, currently unused port number in the subnet from the system in order to bind the generated socket to this port number and to open this port. This, together with the IP address, also makes unique addressing possible for the client.
  • The server learns the complete address of the client from the client's request and can then communicate with it under this complete address.

When assigning port numbers for your own network applications (servers), you should note the following:

  • 1 - 1023: This range of port numbers is intended for standard services (well known services) such as 80 for HTTP or 21 for FTP.
  • 1024 - 49151: Port numbers in this range are also registered but not monitored.
  • 49152 - 65535: These port numbers are automatically assigned by the system for dynamically created sockets, for example.

Note: In socket programming, port 0 has a special meaning because port 0 is a reserved port in networks. This special feature is described in more detail in Chapter 24.1.3.1 UDPSocket projects.

24.1.2.1.3 Server, server socket and communication (data exchange)

The role as a server in a network application is reflected in the following listing, with socket system calls in parentheses:

  1. Create ServerSocket of specific server type (TCP or UDP) as network connection endpoint [ socket() ].
  2. Specify full address: Take IP address in sub-net and bind to specified port [ bind() ].
  3. Start queue - Set maximum number of client requests [ listen(max) ].
  4. Listen for connection requests from clients: Accept incoming client request → Create a communication socket on the server for communication between server and accepted client [ accept() ] or reject the client request.
  5. Network communication: Receive data [ read() ] and send data [ write() ] and monitor status.
  6. Close communication sockets when a client closes the connection to the server [ close() ].
  7. Close server socket [ close() ].

24.1.2.1.4 Server project

A model server - which implements exactly the above seven points - implements a very simple service in the example. The service is that data sent to the server by a client connected to the server is returned to the client with only an 'ok' comment - the server provides the 'OK' service.

Note:Based on the model server, you will be introduced to two server client applications and one client application in the next chapter.

The Gambas source code for a model server is extensively commented:

 [1] ' Gambas class file
 [2]
 [3] Public ServerSocket As ServerSocket
 [4] Public cConnetedSockets As Collection '-- Multi-Client-Betrieb
 [5] Public sIPAddress As String
 [6]
 [7] Public Sub Form_Open()
 [8]
 [9]     Dim sHostname As String
 [10]
 [11]     Shell ("hostname -I | grep -oE '" & Chr$(40) & "[[:digit:]]{1,3}" & Chr$(92) & "." & Chr$(41) & \
 [12]            "{3}[[:digit:]]{1,3}'") To sIPAddress
 [13]     Shell ("hostname") To sHostname
 [14]
 [15]     FMain.Caption = "TCPServer | IP-Adresse: " & Trim(sIPAddress) & " | Hostname: " & Trim(sHostname)
 [16]     cConnetedSockets = New Collection
 [17]
 [18] '-- Es wird ein Server-Socket erzeugt
 [19]     ServerSocket = New ServerSocket As "ServerSocket"
 [20] '-- Der Server-Typ wird auf `Internet Domain Socket` festgelegt
 [21]     ServerSocket.Type = Net.Internet
 [22] '-- Der implementierte Dienst/Service wird an den vorgegebenen Port gebunden (bind())
 [23]     ServerSocket.Port = Val(txbPort.Text)
 [24]
 [25]     btnServiceStartStop.Caption = "Service starten"
 [26]     MAddOns.SetLEDColor(picBoxOnOff, "red")
 [27]
 [28] End
 [29]
 [30] Public Sub btnServiceStartStop_Click()
 [31]
 [32]     If ServerSocket.Status <= Net.Inactive Then
 [33]    '-- Beginnt das Hören am ausgewählten TCP-Port. Optional können Sie auch einen einzelnen Parameter MaxConn übergeben:
 [34]    '-- MaxConn kann 0 (keine Verbindungsbeschränkung) oder größer als 0 sein, was die maximale Anzahl der gleichzeitig
 [35]    '-- aktiven Verbindungen angibt. Dieser Parameter ist optional.
 [36]    '-- Wenn Sie ihn nicht verwenden oder auf 0 setzen, gibt es keine Beschränkung der Anzahl der Client-Verbindungen.
 [37]        ServerSocket.Listen(10)
 [38]    '-- Warten, bis der Server-Socket aktiv ist
 [39]        Repeat
 [40]          Wait 0.001
 [41]        Until ServerSocket.Status = Net.Active
 [42]    '-- Konfiguration ausgewählter Steuer-Elemente
 [43]        txaLog.Clear()
 [44]        cConnetedSockets.Clear()
 [45]        btnServiceStartStop.Caption = "Service stoppen"
 [46]        MAddOns.SetLEDColor(picBoxOnOff, "green")
 [47]        MAddOns.SetNotification("dialog-information", "Hinweis:", ("Der Service wurde gestartet!"))
 [48]        LogMessage("\nDer Server läuft auf " & Trim(sIPAddress) & " und lauscht auf Port " & ServerSocket.Port)
 [49]        LogMessage("\nDer Service wurde um " & Format(Now(), "hh:nn:ss") & " Uhr gestartet!" & "\n")
 [50]     Else
 [51]    '-- Verwenden Sie folgende Methode, um alle vom Server gehaltenen Client-Verbindungen zu schließen und
 [52]    '-- den Abhörvorgang zu stoppen. Alle Connetion-Sockets werden automatisch in den Status `inaktiv` versetzt.
 [53]    '-- Nach dem Anruf der Methode `ServerSocket.Close()` ändert sich der Server-Status auf Net.Inactive.
 [54]        ServerSocket.Close()
 [55]    '-- Warten, bis der Server-Socket inaktiv ist
 [56]        Repeat
 [57]          Wait 0.001
 [58]        Until ServerSocket.Status = Net.Inactive
 [59]    '-- Konfiguration ausgewählter Steuer-Elemente
 [60]        btnServiceStartStop.Caption = "Service starten"
 [61]        MAddOns.SetLEDColor(picBoxOnOff, "red")
 [62]        MAddOns.SetNotification("dialog-information", "Hinweis:", ("Der Service wurde gestoppt!"))
 [63]        LogMessage("\nDer Service wurde gestoppt!")
 [64]        txbCurrentClients.Text = "0"
 [65]        txaLog.Pos = txaLog.Length
 [66]     Endif
 [67]
 [68] End
 [69]
 [70] Public Sub ServerSocket_Connection(RemoteHostIP As String)
 [71]
 [72]     Dim CommunicationSocket As Socket
 [73]     Dim sKey As String
 [74]
 [75] '-- Es wird ein *neuer* Socket auf dem Server erzeugt, wenn der Server eine Client-Verbindungsanfrage akzeptiert hat.
 [76] '-- Dieser Socket wird zur Kommunikation zwischen Server und Client verwendet!
 [77]     CommunicationSocket = ServerSocket.Accept()
 [78] '-- Der neue Socket wird der Liste der aktiven ConnectionSockets auf dem Server hinzugefügt:
 [79]     sKey = Hex$(Rand(0, 2 ^ 32 - 1))
 [80]     cConnetedSockets.Add(CommunicationSocket, sKey)
 [81]
 [82]     txbCurrentClients.Text = Str(cConnetedSockets.Count)
 [83]     LogMessage(Subst("\nVerbindung auf &1 mit Client &2 &3", RemoteHostIP, sKey, "akzeptiert."))
 [84]
 [85] End
 [86]
 [87] Public Sub ServerSocket_Error()
 [88]     LogMessage("Es trat ein Fehler auf!")
 [89] End
 [90]
 [91] ''Socket ist der Socket, über den die Kommunikation Server <-> 'Aktiver Client' abgewickelt wird!
 [92] Public Sub Socket_Read()
 [93]
 [94]     Dim sBuffer As String
 [95]     Dim LastSocket, Socket As Socket
 [96]
 [97] '-- Es wird der zuletzt aktive Client ermittelt
 [98]     LastSocket = Last
 [99] '-- Der Daten-Strom des zuletzt aktiven Clients wird ausgelesen und in `sBuffer` gespeichert
 [100]     Read #LastSocket, sBuffer, Lof(LastSocket)
 [101] '-- Service:
 [102] '-- Die Nachricht des zuletzt aktiven Clients wird mit einem 'ok'-Kommentar an ihn zurück gesendet
 [103]     Write #LastSocket, sBuffer & " (ok)", Len(sBuffer & " (ok)")
 [104] '-- Die Original-Nachricht des zuletzt aktiven Clients wird auf dem Server protokolliert
 [105]     For Each Socket In cConnetedSockets
 [106]       If Socket = Last Then
 [107]          LogMessage("\nDaten von Client " & cConnetedSockets.Key & " empfangen: " & sBuffer)
 [108]       Endif
 [109]     Next
 [110]
 [111] End
 [112]
 [113] ''Socket ist der Socket, über den die Kommunikation Server <-> 'Aktiver Client' abgewickelt wird!
 [114] Public Sub Socket_Closed()
 [115]
 [116]     Dim sCurKey As String
 [117]     Dim Socket As Socket
 [118]
 [119]     For Each Socket In cConnetedSockets
 [120]   '-- Der Client, der sich vom Server abgemeldet hat, wird aus der Liste der aktiven Clients gelöscht
 [121]       If Socket = Last Then
 [122]          sCurKey = cConnetedSockets.Key
 [123]          cConnetedSockets.Remove(sCurKey)
 [124]          LogMessage(Subst("\nClient &1 ist offline.", sCurKey))
 [125]          Break
 [126]       Endif
 [127]     Next
 [128]
 [129]     txbCurrentClients.Text = cConnetedSockets.Count
 [130]     txaLog.Pos = txaLog.Length
 [131]
 [132] End
 [133]
 [134] '-- PRIVAT ---------------------------------------------------------------------------------------------------------
 [135]
 [136] Private Sub LogMessage(sText As String)
 [137]     txaLog.Insert(sText)
 [138]     txaLog.Pos = txaLog.Length
 [139] End
 [140]
 [141] Public Sub Form_Close()
 [142]
 [143]     Dim Socket As Socket
 [144]
 [145] '-- Wenn das Programm beendet wird, dann müssen wir uns von jedem Client trennen, sonst sorgen wir
 [146] '-- für Fehler bei jedem verbundenen Socket und dafür, dass das Programm und auch der Server nur äußerlich
 [147] '-- geschlossen werden, der Socket die Verbindung aber immer noch aufrecht erhält.
 [148]     For Each Socket In cConnetedSockets
 [149]       Socket.Close() '-- Alternative: Close #Socket
 [150]     Next
 [151] '-- Der Server-Socket wird geschlossen - wenn er existiert und aktiv ist
 [152]     If ServerSocket Then
 [153]        If ServerSocket.Status = Net.Active Then ServerSocket.Close()
 [154]     Endif
 [155]
 [156] End
 [157]
 [158] Public Sub btnProgrammEnde_Click()
 [159]     FMain.Close()
 [160] End

24.1.2.1.5 Client project

The model client uses the service offered by the model server. The extensively commented source code is again given in full:

 [1] ' Gambas class file
 [2]
 [3] Public ClientSocket As Socket
 [4]
 [5] Public Sub Form_Open()
 [6]
 [7]     Dim sIPAddress, sHostname As String
 [8]
 [9]     Shell ("hostname -I | grep -oE '" & Chr$(40) & "[[:digit:]]{1,3}" & Chr$(92) & "." & Chr$(41) & \
 [10]            "{3}[[:digit:]]{1,3}'") To sIPAddress
 [11]     Shell ("hostname") To sHostname
 [12]     FMain.Caption = "TCPClient | IP-Adresse: " & Trim(sIPAddress) & " | Hostname: " & Trim(sHostname)
 [13]     btnSendData.Enabled = False
 [14]     txbHost.SetFocus()
 [15]     MAddOns.SetLEDColor(picBoxOnOff, "red")
 [16]
 [17] End
 [18]
 [19] Public Sub btnConnectDisconnect_Click()
 [20]
 [21]      If Not txbHost.Text Then
 [22]         Message.Warning("<hr>\nEs wurde <b>keine</b> IP-Adresse für den Server angegeben!\n<hr>")
 [23]         txbHost.SetFocus()
 [24]         Return
 [25]      Endif
 [26]
 [27]      If btnConnectDisconnect.Caption = "Zum Server verbinden" Then
 [28]
 [29]     '-- Client-Socket erzeugen
 [30]         ClientSocket = New Socket As "ClientSocket"
 [31]     '-- IP-Adresse des Servers festlegen
 [32]         ClientSocket.Host = txbHost.Text
 [33]     '-- Port des Dienstes auf dem Server festlegen
 [34]         ClientSocket.Port = Val(txbPort.Text)
 [35]     '-- Zum Chat-Server verbinden
 [36]         ClientSocket.Connect()
 [37]
 [38]         txaChatHistory.Clear()
 [39]
 [40]         Do While (ClientSocket.Status <> Net.Connected) And (ClientSocket.Status > Net.Inactive)
 [41]           Wait 0.001
 [42]         Loop
 [43]     '-- Entweder ist der Client-Status = 7 (Net.Connected) oder der Client-Status < 0 -> Fehler!
 [44]         If ClientSocket.Status = Net.Connected Then
 [45]            btnConnectDisconnect.Caption = "Vom Server trennen"
 [46]            MAddOns.SetLEDColor(picBoxOnOff, "green")
 [47]            btnSendData.Enabled = True
 [48]            txbMessage.Enabled = True
 [49]         Else
 [50]            Message.Warning("<hr>\nEs ist <b>kein</b> Server erreichbar! IP-Adresse und Port korrekt?\n<hr>")
 [51]         Endif
 [52]      Else
 [53]     '-- Den Client-Socket schließen ...
 [54]         ClientSocket.Close()
 [55]         Wait 0.1
 [56]         If ClientSocket.Status = Net.Inactive Then
 [57]            MAddOns.SetLEDColor(picBoxOnOff, "red")
 [58]            btnConnectDisconnect.Caption = "Zum Server verbinden"
 [59]            btnSendData.Enabled = False
 [60]            LogMessage("\nDie Verbindung zum Server wurde durch den Client getrennt!")
 [61]         Endif
 [62]     Endif
 [63]
 [64] End
 [65]
 [66] '' -- Dieses Ereignis wird ausgelöst, nachdem eine TCP/IP-Verbindung vom Client zum Server
 [67] '' -- erfolgreich hergestellt wurde. Die Status-Eigenschaft wird auf den Wert `Net.Connected` gesetzt.
 [68] Public Sub ClientSocket_Ready()
 [69]     LogMessage("\nEine TCP/IP-Verbindung zum Server auf Host " & ClientSocket.Host & " wurde hergestellt!")
 [70]     LogMessage("Die Client-Adresse ist " & ClientSocket.LocalHost & ":" & Str(ClientSocket.LocalPort) & Chr(10))
 [71]     txbHost.SetFocus()
 [72] End
 [73]
 [74] Public Sub ClientSocket_Read()
 [75]
 [76]     Dim sBuffer As String
 [77]
 [78] '-- Der Daten-Strom vom Server wird ausgelesen und in der Variablen `sBuffer` gespeichert
 [79]     Read #ClientSocket, sBuffer, Lof(ClientSocket)
 [80] '-- Der Inhalt von `sBuffer` wird angezeigt
 [81]     LogMessage("◀-- " & sBuffer)
 [82]     txbMessage.SetFocus()
 [83]
 [84] End
 [85]
 [86] Public Sub ClientSocket_Closed()
 [87]     LogMessage("\nDie Verbindung wurde vom Server geschlossen!")
 [88]     btnSendData.Enabled = False
 [89]     txbMessage.Enabled = False
 [90]     btnConnectDisconnect.Caption = "Zum Server verbinden"
 [91]     MAddOns.SetLEDColor(picBoxOnOff, "red")
 [92] End
 [93]
 [94] Public Sub btnSendData_Click()
 [95]     If Not txbMessage.Text Then Return
 [96]     If ClientSocket.Status = Net.Connected Then
 [97]        Write #ClientSocket, txbMessage.Text, Len(txbMessage.Text)
 [98]        LogMessage("--▶ " & txbMessage.Text)
 [99]     Else
 [100]        LogMessage("Es besteht keine Verbindung zum Server!")
 [101]     Endif
 [102]     txbMessage.Clear()
 [103] End
 [104]
 [105] '-- PRIVAT ------------------------------------------------------------------------------------------------------------
 [106]
 [107] Private Sub LogMessage(sText As String)
 [108]     txaChatHistory.Insert(sText & "\n")
 [109]     txaChatHistory.Pos = txaChatHistory.Length
 [110] End
 [111]
 [112] Public Sub Form_Close()
 [113]     If ClientSocket And If ClientSocket.Status = Net.Connected Then
 [114]        ClientSocket.Close()
 [115]     Endif
 [116] End
 [117]
 [118] Public Sub btnClose_Click()
 [119]     FMain.Close()
 [120] End

24.1.2.1.6 Example server-client application

For the test of the server-client application, server and client 1 are started on the same PC. However, it is also possible that you start the server on PC1 and client 1 on PC2. It is only important that server and client 1 are in the same network for the test. This constellation is presented in chapter '24.1.2.2 Socket projects'.

On the server, the complete communication with each client and the various status messages are logged, while the clients display the communication and some status messages about the TCP connection.

Test protocol:

S1
Figure 24.1.2.1.1: Start Server with 'OK' Service

The server starts with the IP address 192.168.0.3 and listens on the fixed port 8088. The port entry in the text field can be enabled with … if you want to use a different port. Observe the notes in Chapter '24.1.2.1.2 Socket' in the section where specific port ranges are introduced. Enter the above IP address 192.168.0.3 or 'localhost' as the address for client 1, as the server and client 1 are started on the same computer in this test:

C1
Figure 24.1.2.1.2: Server address: localhost

Start client 1 with 'Connect to server'. The server accepts client 1 on port 46146!

S2
Figure 24.1.2.1.3: The server logs the connection acceptance

C2

Figure 24.1.2.1.4: Server-client connection can now be used

C3
Figure 24.1.2.1.5: Text input

Now you can enter text in the text field and send it to the server with 'Send', whose receipt the server logs:

S3
Figure 24.1.2.1.6: Receiving data (server)

The server then performs its service and sends the received text back to client 1 with the 'OK' acknowledgement.

C4
Figure 24.1.2.1.7: Service in action

Client 1 then disconnects from the server after 'Disconnect from Server', which the server acknowledges with an 'Offline' message and with a change in the number of connected clients:

S4
Figure 24.1.2.1.8: Offline message from client with port 46146 (client 1)

Finally, 'Stop Service' closes the client and thus stops the service offered …

S6
Figure 24.1.2.1.9: The service is stopped

… and the server is terminated with 'End'.

Download

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k24/k24.1/k24.1.2/k24.1.2.1/start.txt · Last modified: 06.09.2022 (external edit)

Page Tools