Die Community zu .NET und Classic VB.
Menü

Winsock Programmierung

 von 

Einleitung 

In der letzten Folge habe ich gezeigt, wie Du mit dem Winsock-Control einen einfachen Chat programmieren kannst. In dieser Folge gehe ich ein wenig weiter. Dieses mal ist ein Chat an der Reihe, in dem mehrere Personen zusammen chatten können.

Wenn Du den vorigen Artikel nicht gelesen hast, würde ich das empfehlen.

Mit freundlichen Grüßen
Patrice Neff

Vorwort  

Bei dem Chat, den ich hier vorstelle, ist ein Chat-Server nötig. Dessen IP muss jedem Chatter bekannt sein. Danach können alle Benutzer zu diesem Server verbinden, um miteinander zu chatten. Der Server muss also die verschiedenen Benutzer verwalten. Nun kann aber mit dem Winsock-Control nur eine Verbindung geöffnet werden. Wie ist es denn möglich, mehrere Benutzer auf den Server zu lassen? Die Antwort ist einfach: Mit Hilfe eines Steuerelementfeldes (Array). Zur Laufzeit werden dynamisch Winsock-Controls hinzugeladen. Mit jedem geladenen Control kann genau eine Verbindung geöffnet sein. Aber der Reihe nach...

Der Nachrichtenaufbau  

Bei unserem ersten Beispiel war der Aufbau der Nachrichten so einfach wie es nur geht. Erst 50 Zeichen für den Namen und dahinter kam die Nachricht. Das reicht für dieses Beispiel nicht mehr. Denn jetzt identifizieren sich die Clients bei dem Server. Deshalb wird das erste Zeichen der Datei dazu verwendet, den Nachrichten-Typ zu kennzeichnen. Wenn dieses erste Zeichen eine Null ist, handelt es sich um eine Nachricht eines Benutzers. (z.B. "Hallo Hansi") Steht jedoch eine Eins am Anfang, so handelt es sich um eine Identifikation. Bei dieser werden 51 Zeichen übermittelt. (Die Eins und der Name des Benutzers)

Nachrichten durch die Leitungen senden  

Das Versenden von Nachrichten übernimmt wieder die Prozedur Senden, an der wir jedoch leichte Änderungen vornehmen müssen, da die Winsock-Controls neu mit einem Index versehen sind. Sehen wir uns die Sub mal an:

Sub Senden(strData As String, Optional Index As Integer = 0)
    blnSendCompleted = False
    If wsckChat(Index).State = sckConnected Then
        wsckChat(Index).SendData strData
        Do Until blnSendComplted
            DoEvents
        Loop
    End If
End Sub

Erklärungen: Geändert hat sich, dass neu ein Parameter Index übergeben wird. Dieser ist jedoch optional, muss also nicht zwingend Angegeben werden, wodurch die Sub abwärtskompatibel wird. Standardmässig wird der Index 0 verwendet.

Nachrichten an die Clients senden  

Ein Client kann nur an den Server senden, nicht aber an den Benutzer direkt. Deshalb muss der Server die reinkommenden Nachrichten an alle Clients weiterleiten. Dies geschieht mit der folgenden Methode ForwardMsg.

Sub ForwardMsg(strData As String, intExcludeIndex As Integer)
Dim intCounter As Integer
    If wsckChat.Count > 1 Then
        For intCounter = 1 To wsckChat.Count - 1
            If intCounter <> intExcludeIndex Then
            Senden strData, intCounter
            End If
        Next
    End If
End Sub

Erklärungen: Diese Funktion durchläuft alle geladenen Winsock-Controls. Für jedes Control wird geprüft, ob eine Verbindung offen ist. Ist dies der Fall, ruft das Programm die Funktion Senden auf, um die Nachricht zu verschicken.

Die Methode Listen  

Auch in diesem Beispiel verwenden wir wieder die Methode Liste, die wir bereits im erste Teil verwendet haben. (Wenn dir das nichts sagt, dann ab zum ersten Teil ;-)

Sub cmdListen_Click()
    strNick = Left(txtName & Space(50), 50)
    blnServer = True
    wsckChat(0).LocalPort = 12123
    wsckChat(0).Listen
End Sub

Erklärungen: Der Code sieht wieder sehr ähnlich aus. Da aber unser Winsock-Control jetzt ein Array ist, müssen wir einen Index verwenden. Das Haupt-Control, welches wir für Listen verwenden, hat den Index 0. Ausserdem kommt die Variable blnServer hinzu. Diese ist für das ganze Formular gültig und gibt an, ob die aktuelle Programm-Instanz ein Server oder ein Client ist.

Die Kontaktaufnahme  

Auch hier wird wieder das Event ConnectionRequest gefeuert, sobald ein Client Kontakt aufnimmt. Aber wir können jetzt nicht den Code verwenden, den wir noch im ersten Beispiel verwendet haben. Der Grund ist, dass wir das Control mit dem Index Null nicht schliessen dürfen. Schliesslich muss dieses die Verbindungsversuche für die kommenden Benutzer beantworten. Deshalb wird hier ein zusätzliches Winsock-Control hinzugeladen.

Sub wsckChat_ConnectionRequest(Index As Integer, ByVal requestID As Long)
    wsckChat(GetNextFreeIndex).Accept requestID
End Sub

Erklärungen: Komisch, nicht. Wieso wird hier nur eine Zeile benötigt? Das Geheimnis liegt in der Funktion GetNextFreeIndex!

Function GetNextFreeIndex() As Integer
    Dim intCounter As Integer
    For intCounter = 1 To wsckChat.Count - 1
        If wsckChat(intCounter).State = sckClosed Then
            GetNextFreeIndex = intCounter
            Exit Function
        End If
    Next
    GetNextFreeIndex = wsckChat.Count
    Load wsckChat(GetNextFreeIndex)
End Function

Erklärungen: Diese Funktion ist doch ein bisschen grösser. Die Aufgabe der Funktion ist, den Index des ersten geschlossenen Winsock-Controls (State = sckClosed) zurückzugeben. Wenn kein geschlossenes Control gefunden wird, sorgt die Funktion auch gleich für Nachschub und lädt ein zusätzliches Control.

Kaum verändert: Der Client  

Sub cmdConnect_Click()
Dim strRemoteComputer As String
    strNick = Left(txtName & Space(50), 50)
    strRemoteComputer = InputBox("RemoteHost:")
    If Trim(strRemoteComputer) = "" Then Exit Sub
    blnServer = False
    wsckChat(0).RemotePort = 12123
    wsckChat(0).RemoteHost = strRemoteComputer
    wsckChat(0).Connect
End Sub

Erklärungen: Wir Du siehst, ändert sich an dem Code so gut wie nichts. Die einzige Änderung ist, dass jetzt über einen Index auf das Winsock-Control zugegriffen werden muss. Der Client greift immer über das Control mit dem Index 0 auf den Server zu. Auch hier kommt noch die Variable blnServer dazu.

Ausserdem kommt noch folgender Code hinzu:

Sub wsckChat_Connect(Index As Integer)
    If blnServer = False Then
        Senden "1" & strNick
    End If
End Sub

Erklärung: Mit diesem Code erreichen wir, dass sich ein Client beim Server identifiziert. wsckChat_Connect wird aufgerufen, sobald der Server die Methode Accept aufruft.

Nachrichten senden  

Bereits jetzt können sich verschiedene Benutzer auf dem Server einloggen. Jetzt folgt noch die Möglichkeit, dass die Benutzer Nachrichten senden könen. Die dazu nötigen Methoden Senden und ForwardMsg haben wir ja bereits implementiert.

Das wichtigste ist, dass wir beim Senden unterscheiden müssen, ob die aktuelle Instanz als Server oder als Client läuft. Denn läuft sie als Server, muss die eingegebene Nachricht an alle verbundenen Benutzer gesendet werden. Der Client sendet die Nachricht an den Server.

Sub cmdSend_Click()
Dim strMessage As String
    strMessage = "0" & strNick & txtNachricht.Text
    If blnServer Then
        ForwardMsg strMessage, 0
    Else
        Senden strMessage, 0
    End If
    AddMessage txtNachricht.Text, strNick
End Sub

Erklärungen: Als erstes wird der String zusammengebaut, welcher über das Netzwerk versendet wird. Dieser besteht aus einer führenden 0, da es sich um eine normale Nachricht handelt. Danach kommt der Nick und anschliessend der eingegebene Text. Dann unterscheidet das Programm zwischen Server/Client. Wenn die Instanz als Server läuft, wird die Nachricht an alle verbundenen Clients weitergeleitet. Bei einem Client wird die Nachricht an den Server geschickt.

Daten empfangen  

Nun folgt ein sehr wichtiger Teil: Die ankommenden Daten müssen verarbeitet werden. Auch hier haben Server und Client unterschiedliche Aufgaben. Der Server muss Nachrichten an alle Clients weiterleiten. Ausserdem muss er dafür sorgen, dass sich die Clients anmelden können.

Sub wsckChat_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim strData As String, strNick As String, strMessage As String
    wsckChat(Index).GetData    strData
    If Left(strData, 1) = "0" Then
        strNick = Trim(Mid(strData, 2, 50))
        strMessage = Mid(strData, 52)
        AddMessage strMessage, strNick
        If blnServer Then ForwardMsg strData, Index
    ElseIf Left(strData, 1) = "1" Then
        strNick = Trim(Mid(strData, 2, 50))
            If blnServer Then
                wsckChat(Index).Tag = strNick
                ForwardMsg Left("-system-" & Space(50), 50) & "1" & strNick, Index
            End If
        AddMessage "Der User " & strNick & " betritt den Chat.", "-system-"
    End If
End Sub

Erklärungen: Nach dem Einlesen der einkommenden Daten wird das erste Zeichen der Daten geprüft. Handelt es sich dabei um eine Null, so kommt eine normale Nachricht herein, welche ausgegeben und evtl. an die Clients weitergeleitet werden muss. Steht jedoch eine Eins an erster Stelle, loggt sich ein Client ein. Dann wird eine Nachricht ausgeben, dass ein neuer User den Chat betreten hat und die Clients werden informiert.

Beispiel als Download  

Endlich am Ende! ;-) Wie Du siehst, ist die Programmierung eines Chats, der mehrere Benutzer zulassen soll, bereits ein wenig komplexer. Doch viele Ideen habe ich hier noch nicht eingebaut. Ein paar Ideen, damit Du Dein Wissen nun ein wenig festigen kannst: Alle User auflisten, private Nachrichten, mehrere Channels, etc. Sei einfach kreativ ;-)

Original des Tutorials auf http://www.patrice.ch/de/computer/programming/visualbasic/tips/winsock2

Beispielprojekt [7654 Bytes]

Ihre Meinung  

Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.