User Tools

Site Tools


Sidebar

Network and communication

k24:k24.1:k24.1.2:k24.1.2.2:start

24.1.2.2 Socket Projects

Sockets as an interface for programming network applications are used in all three projects presented to you in this chapter. Among others, the two classes ServerSocket and Socket are used.

  • The first project consists of a server and a client programme. The server provides a simple chat service that can be used by several clients.
  • A server provides a quote service in the second project. Clients can connect to the server and request a short or a long quote by sending a certain string, which the server delivers to the client.
  • In the third project, a client retrieves the current time from a time server on the Internet on port 37 and outputs it formatted.

For the last project, the source code is given in full in the chapter. All three project archives can be found in the download area.

24.1.2.2.1 Project 1 - Chat Service

In the first project, a server socket is used in the chat server, as well as sockets for each running connection. Only one socket is used in the chat client. As a service, the chat server offers a simple chat service on port 8088. If you want to use the service, you must know the IP address of the server and the port under which the server offers its service. The chat server and a chat client A are started on computer 1 (IP address 192.168.2.102). Therefore, specifying the server IP address 127.0.0.1 (local loopback address) on client A is just as correct as the alternative 192.168.2.102:


Figure 24.1.2.2.1: Chat server and chat client A

On the server, the complete chat history and various status messages are logged, while for the clients, the chat history and status messages about the TCP connection are displayed.For a test of the server-client application, there is another chat client B on computer 2 (laptop). Client B on computer 2 must select the server IP address 192.168.2.102. Attention: The IP address of the server always depends on the (local) network in which the computer with the server is located! The port is already preset to 8088 on the server and the clients.


Figure 24.1.2.2: Chat client B on computer 2

The sufficiently commented source code is only given in excerpts:

[1] Public Sub ServerSocket_Connection(RemoteHostIP As String)
[2]
[3]     Dim ConnectedSocket As Socket
[4]     Dim ConnectionSocket As Socket
[5]     Dim sBuffer As String
[6]     Dim k As Integer
[7]
[8]     If ServerSocket.Status <= Net.Active Then Return
[9]
[10] '-- Es wird ein *neuer* Socket auf dem Server erzeugt, wenn der Server eine Client-Verbindungsanfrage
[11] '-- akzeptiert hat. Dieser Socket wird zur Kommunikation zwischen Server und Client verwendet!
[12]     ConnectionSocket = ServerSocket.Accept()
[13]
[14] '-- Der neue Socket wird der Liste der aktiven ConnectionSockets auf dem Server hinzugefügt:
[15]     aConnetedSockets.Add(ConnectionSocket)
[16]
[17] '-- Wenn eine Verbindungsanfrage von einem neuen Client vom Server akzeptiert wurde, dann wird eine
[18] '-- Nachricht an alle mit dem ChatServer verbundenen Clients gesendet, nur nicht an den ersten Client.
[19]     If aConnetedSockets.Count > 1 Then
[20]        If aConnetedSockets.Count = 2 Then
[21]           sBuffer = "Es ist noch genau ein weiterer Chat-Client online."
[22]        Else
[23]           sBuffer = "Es sind noch weitere " & Str(aConnetedSockets.Count - 1)&" Chat-Clients online."
[24]        Endif
[25]        For k = 0 To aConnetedSockets.Max
[26]          ConnectedSocket = aConnetedSockets[k]
[27]          Write #ConnectedSocket, sBuffer, Len(sBuffer)
[28]        Next
[29]     Endif
[30]
[31]     txbCurrentClients.Text = Str(aConnetedSockets.Count)
[32]     LogMessage(Subst("Verbindung vom Chat-Client auf &1 &2",RemoteHostIP,"akzeptiert.") & gb.NewLine)
[33]
[34] End
[35]
[36] ''Socket ist der Socket, über den die Kommunikation Server <-> 'Aktiver Client' abgewickelt wird
[37] Public Sub Socket_Read()
[38]
[39]     Dim sBuffer As String
[40]     Dim ConnectionSocket As Socket
[41]     Dim ConnectedSocket As Socket
[42]
[43] '-- Es wird der zuletzt aktive Client ermittelt
[44]     ConnectionSocket = Last
[45] '-- Der Daten-Strom des zuletzt aktiven Clients wird ausgelesen und in `sBuffer` gespeichert
[46]     Read #ConnectionSocket, sBuffer, Lof(ConnectionSocket)
[47] '-- Run Service:
[48] '-- Die Chat-Nachricht des zuletzt aktiven Chat-Clients wird an *alle* mit dem Chat-Server
[49] '-- verbundenen Clients gesendet!
[50]     For Each ConnectedSocket In aConnetedSockets
[51]       Write #ConnectedSocket, sBuffer, Len(sBuffer)
[52]     Next
[53]
[54] '-- Die Chat-Nachricht wird auf dem Server protokolliert
[55]     LogMessage(sBuffer)
[56]
[57] End

24.1.2.2.2 Project 2 - Quote Service

In order to use the citation service of the server used and not just receive a message that the requested service is currently unavailable, you should install the (German) collection of citations on the computer on which the server is started:

sudo apt install fortune-mod	        ' Zitat-Programm
sudo apt-get install fortunes-de	' Zitat-Sammlung (DE)

The following is a short test description for a server offering a citation service and for a client on the same computer:

  • First, the citation server and a client are started on one computer. Then the communication - in this case the use of the citation service of the server - can begin.
  • With -l (long) or -s (short), the client requests a long or a short quote.
  • Finally, the server's service can be terminated or the client can disconnect from the server. In both cases, these events are logged.


Figure 24.1.2.3: Quote server and client 1 in action

If you take a closer look at the source codes for project 1 and project 2, you will notice that they only differ in the service offered by the server and in the presentation of the transmitted data to the client. This leaves plenty of room for projects with their own services!

24.1.2.2.3 Project 3 - Client for a time service

In the final project, a client uses the time service of a selected time server on the Internet on port 37. The list in a combo box contains four time servers that are considered to be in good standing. When a client successfully connects to the time server, it sends the current time in a special format and immediately closes the TCP connection:

B1
Figure 24.1.2.2.4: Client on port 37 - output of the current date and time

If the time server is not reachable, then this is indicated. The error is initiated here because the country identifier was specified incorrectly with 'ita' instead of 'it':

B2
Figure 24.1.2.2.5: Client with status comment

The connection is terminated after a fixed time set in the source code. Since, according to B. Minisini (September 2020), the Socket.Timeout property is not used as a connection timeout by the connect() method, a separate TimeOut procedure is defined in the programme in lines 44 to 53.Obviously, no time server can be reached at the specified IP address within the specified time span (2 seconds):

B3
Figure 24.1.2.6: Client after a timeout

The source code for the client is given in full:

[1] ' Gambas class file
[2]
[3] '-- Liste deutscher Zeitserver: http://www.hullen.de/helmut/filebox/DCF77/ntpsrvr.html
[4] '-- Test1:  130.133.1.101       -> Fehler TimeOut
[5] '-- Test2:  time.fu-berlin.net  -> Fehler `Zeit-Server nicht gefunden`
[6]
[7] Public lTimeResult As Long
[8] Private iCurrentHost As Integer
[9]
[10] Public Sub Form_Open()
[11]     FMain.Center()
[12]     FMain.Resizable = False
[13]     SetLEDColor(picStatus, "red")
[14] '-- Vorgabe einer Liste mit Zeit-Servern
[15]     cmbHost.Add("134.130.4.17") '-- RWTH Aachen -> timeserver.rwth-aachen.de
[16]     cmbHost.Add("time.ien.it")
[17]     cmbHost.Add("130.133.1.10") '-- time.fu-berlin.de
[18]     cmbHost.Add("time.fu-berlin.de")
[19] '-- Auswahl eines stabilen deutschen Zeit-Servers
[20]     If cmbHost.List.Count > 3 Then cmbHost.Text = cmbHost.List[3]
[21]     lblStatus.Foreground = Color.Gray
[22]     lblStatus.Caption = "Verbindung zum Zeit-Server ist geschlossen."
[23] End
[24]
[25] Public Sub btnConnect_Click()
[26]     txbDateTime.Clear()
[27]     lblStatus.Foreground = Color.Black
[28]     btnConnect.Enabled = False
[29]     btnConnect.SetFocus()
[30] '-- TCP-Verbindung initialisieren (Host und Port)
[31]     TCP_Socket.Host = cmbHost.Text
[32]     If IsInteger(txbPort.Text) Then TCP_Socket.Port = Val(txbPort.Text)
[33]  '-- Verbindung zum Server herstellen
[34]     TCP_Socket.Connect()
[35]     If TCP_Socket.Status > Net.Inactive Then
[36]        btnDisconnect.Enabled = True
[37]        lblStatus.Text = "Verbindung zum Zeit-Server wird aufgebaut ..."
[38]        TimeOut.Delay = 2000 ' TimeOut = 2 Sekunden
[39]        TimeOut.Start()
[40]        SetLEDColor(picStatus, "green")
[41]     Endif
[42] End
[43]
[44] Public Sub TimeOut_Timer()
[45]     TimeOut.Stop()
[46]     If TCP_Socket.Status <> Net.Connected Or lTimeResult = 0 Then
[47]        If TCP_Socket.Status > 0 Then Close #TCP_Socket
[48]        Set_Interface(False)
[49]        lblStatus.Text = ("T I M E O U T")
[50]        SetLEDColor(picStatus, "red")
[51]        FMain.Caption = "Client-Socket  *  Port 37  *  TCP"
[52]     Endif
[53] End
[54]
[55] Public Sub TCP_Socket_Found()
[56] '-- Dieses Ereignis wird ausgelöst, wenn der Hostname erfolgreich
[57] '-- in die Host-IP-Adresse aufgelöst wurde
[58]     lblStatus.Caption = "Hostname in IP-Adresse aufgelöst ..."
[59] End
[60]
[61] Public Sub TCP_Socket_Ready()
[62] '-- Das Ereignis wird ausgelöst, nachdem eine Verbindung zwischen
[63] '-- Client und Server erfolgreich hergestellt wurde.
[64]     TimeOut.Enabled = False
[65]     lblStatus.Text = "Verbunden..." & TCP_Socket.Path
[66]     FMain.Enabled = True
[67]     Set_Interface(True)
[68] End
[69]
[70] Public Sub TCP_Socket_Read()
[71]     Dim sResult, sDatum, sZeit, sShellOutput As String
[72]     Dim i, iOffset As Integer
[73]     Dim iNTPSekunden As Long
[74]     Dim iCurrentSekunden As Integer
[75]     Dim iSekunden19001970 As Long
[76]     Dim dDate1970, dCurrentDateUTC As Date
[77]
[78] '-- In Deutschland gilt UTC+1 als Normalzeit und UTC+2 als Sommerzeit.
[79] '-- Der Zeitstempel im NTP ist 64 Bits lang.
[80] '-- 32 Bits kodieren die iNTPSekunden seit dem 1. Januar 1900 00:00:00 Uhr (!)
[81]     If TCP_Socket.Status = Net.Connected Then
[82]        Read #TCP_Socket, sResult, Lof(TCP_Socket)
[83]    '-- Umwandlung des übermittelten Datenwortes in eine ganze Zahl
[84]        For i = 1 To Len(sResult)
[85]          iNTPSekunden = iNTPSekunden * 256 + Asc(Mid$(sResult, i, 1))
[86]        Next
[87]     Endif
[88] '-- Alternative: Anzahl der Sekunden = b3*256³ + b2*256² + b1*256 + b0
[89]     lTimeResult = iNTPSekunden
[90]     iSekunden19001970 = DateDiff("01/01/1900", "01/01/1935", gb.Second) + DateDiff("01/01/1935", "01/01/1970 ", \
[91]                         gb.Second)
[92]     iCurrentSekunden = iNTPSekunden - iSekunden19001970
[93]     dDate1970 = Date(1970, 01, 01, 0, 0, 0)
[94] '-- Bestimmung der lokalen Zeit
[95]     Shell "date +%Z" To sShellOutput
[96] '-- 0 => UTC, 3600 => Normalzeit (CET), 7200 => Sommerzeit -> Central European Summer Time (CEST)
[97]     If Trim(sShellOutput) = "CEST" Then
[98]        iOffset = 7200
[99]        lblTZ.Text = "MESZ"
[100]     Else
[101]        iOffset = 3600
[102]        lblTZ = "MEZ"
[103]     Endif
[104]     dCurrentDateUTC = DateAdd(dDate1970, gb.Second, iCurrentSekunden + iOffset)
[105]     sDatum = Format$(dCurrentDateUTC, "dddd") & ", " & Format$(dCurrentDateUTC, "d. mmmm yyyy")
[106]     sZeit = Format$(Time(dCurrentDateUTC), "hh:nn:ss") & " Uhr"
[107]     txbDateTime.Text = " " & sDatum & " - " & sZeit
[108]     iOffset = 0
[109]     dCurrentDateUTC = DateAdd(dDate1970, gb.Second, iCurrentSekunden + iOffset)
[110]     sZeit = Format$(Time(dCurrentDateUTC), "h:nn")
[111]     FMain.Caption = "Client-Socket  *  Port 37  *  TCP  " & String.Chr(187) & "  " & sZeit & " UTC"
[112]     SetLEDColor(picStatus, "red")
[113]
[114] End
[115]
[116] Public Sub TCP_Socket_Error()
[117]     Select Case TCP_Socket.Status
[118]       Case Net.CannotCreateSocket
[119]         lblStatus.Text = "Socket generieren nicht erlaubt."
[120]       Case Net.HostNotFound
[121]         lblStatus.Text = "Zeit-Server nicht gefunden."
[122]         FMain.Caption = "Client-Socket  *  Port 37  *  TCP"
[123]       Case Net.ConnectionRefused
[124]         lblStatus.Text = "Verbindung zum Zeit-Server nicht möglich."
[125]       Case Net.CannotRead
[126]         lblStatus.Text = "Fehler beim Lesen des Zeitstempels."
[127]     End Select
[128]     Set_Interface(False)
[129] End
[130]
[131] Public Sub TCP_Socket_Closed()
[132]     lblStatus.Foreground = Color.Gray
[133]     lblStatus.Caption = "Verbindung zum Zeit-Server ist geschlossen."
[134]     FMain.Enabled = True
[135]     Set_Interface(False)
[136] End
[137]
[138] Public Sub btnDisconnect_Click()
[139]     Try TCP_Socket.Close()
[140]     Set_Interface(False)
[141]     lblStatus.Text = "Verbindung zum Zeit-Server ist geschlossen."
[142]     SetLEDColor(picStatus, "red")
[143]     btnDisconnect.SetFocus()
[144] End
[145]
[146] Public Sub cmbHost_Click()
[147]     iCurrentHost = cmbHost.Index
[148] End
[149]
[150] Public Sub cmbHost_Change()
[151]     If TCP_Socket.Status > 0 Then Close #TCP_Socket
[152]     lblStatus.Foreground = Color.Gray
[153]     lblStatus.Caption = "Verbindung zum Zeit-Server ist geschlossen."
[154]     txbDateTime.Clear()
[155]     lblTZ.Text = ""
[156]     SetLEDColor(picStatus, "red")
[157] End
[158]
[159] Private Sub Set_Interface(bState As Boolean)
[160]     btnConnect.Enabled = Not bState
[161]     txbPort.Enabled = Not bState
[162]     btnDisconnect.Enabled = bState
[163]     TimeOut.Enabled = bState
[164]     SetLEDColor(picStatus, "red")
[165] End
[166]
[167] Private Sub SetLEDColor(picBox As PictureBox, sLEDColor As String)
[168]     picBox.Picture = Picture["LED/led_" & Lower(sLEDColor) & ".svg"]
[169] End
[170]
[171] Public Sub btnClose_Click()
[172]     FMain.Close()
[173] End
[174]
[175] Public Sub Form_Close()
[176]     If TCP_Socket.Status > 0 Then Close #TCP_Socket
[177] End

Notes:

  • Four stable time servers known to provide reliable service are used.
  • At http://www.hullen.de/helmut/filebox/DCF77/ntpsrvr.html you will find a list of German time servers compiled by Helmut Hullen.
  • The main load in the programme is carried by the TCP_Socket_Read() event. First the time is read, then processed and finally output formatted as daylight saving time or standard time (→ Figure 24.1.2.2.4).

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.2/start.txt · Last modified: 18.06.2022 (external edit)

Page Tools