Winsock Programmierung
von Patrice Neff
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.