Intro
Wenn man mich bisher gefragt hat, wie man mit dem Winsock-Control umgeht habe ich immer geantwortet "Suche in der MSDN nach Chat". Doch mittlerweile wurde mir gesagt, dass diese Samples da nicht unbedingt einfach zu verstehen seien. Auch wird die Möglichkeit, mehrere Benutzer gleichzeitig zu "verarbeiten" nur am Rande erwähnt. Einen Chat, der mehrere Benutzer zulässt werde ich in der nächsten Folge zeigen.
Formular zusammenstellen
Als erstes solltest du das Formular zusammenstellen. Um die umfangreichen Erklärungen zu deren Aufbau sparen zu können, biete ich das Formular zum Download an. Die Form in der ZIP-File enthält noch keinerlei Code.
Listen und Connect. Hu?
Um mit dem Winsock-Control umgehen zu können ist das
Verständnis zweier Methoden wichtig. Es geht um die
Methoden Connect und
Listen.
Die Methode Listen wird verwendet, um als Server zu
fungieren. Die Methode Connect um zu einem Server zu
verbinden. Ich verwende dafür normalerweise die folgende
Vorstellung: Ein Webserver wird beim Programmstart ein Listen
im Code enthalten. Während ein Browser bei jedem Zugriff
auf eine Website einen Connect ausführt. Im
Multi-User-Chat, den ich in der nächsten Folge zeigen
werde, sieht das dann so aus, dass ein Benutzer als Server
fungiert. Diese Programminstanz wird die Methode Listen
verwenden. Alle User, die nun an dem Chat teilnehmen wollen,
werden einen Connect ausführen müssen.
Senden von Daten
Nachdem eine Verbindung besteht (dazu nachher mehr)
können Daten ausgetauscht werden. Die geschieht sehr
einfach mit der Methode SendData, welcher die
zu sendenden Daten als String übergeben
werden. Allerdings gibt es hier einige Tücken zu
beachten. Wenn diese Funktion in einer Schleife x-mal
nacheinander ausgeführt wird, kommt es zu Fehlern. Denn beim
Senden der Daten kann (und wird es im Allgemeinen) zu
Verzögerungen kommen. Deshalb arbeite ich mit einer Funktion,
welche eine Pause einlegt, bis die Daten wirklich gesendet
sind. Diese Funktion sieht folgendermassen aus:
Private Sub Senden(strData As String)
blnSendCompleted = False
wsckChat.SendData strData
Do Until blnSendCompleted
DoEvents
Loop
End Sub
Erklärungen: Die Variable blnSendCompleted ist im
Formular-Kopf als Boolean definiert. Diese wird in der Sub
wsckChat_SendComplete auf True gesetzt. Das Event SendComplete
des Winsock-Controls wird ausgelöst, wenn die Daten fertig
gesendet sind. Das ist die beste mir bekannte Möglichkeit,
für das Senden von Daten.
Nachrichten anzeigen
In diesem Beispiel wird für das Anzeigen von Nachrichten eine
Multiline-TextBox verwendet. Das ist zwar keine sehr
komfortable Lösung, aber auch nicht wirklich schlecht. Und
schliesslich soll es ja nur ein Beispiel sein ;-) Auch das
Anzeigen von Nachrichten wurde in eine Sub ausgelagert:
Private Sub AddMessage(strMessage As String, strSender As String)
txtChat.Text = txtChat.Text & _
"(" & Trim(strSender) & ") " & _
strMessage & vbCrLf
txtChat.SelStart = Len(txtChat.Text)
End Sub
Erklärungen: Dieser Code ist nicht sonderlich
aufregend. Als erstes wird der neue Text inklusive Absender in
der TextBox ans Ende geschrieben. Danach wird noch
sichergestellt, dass auch das Ende der TextBox sichtbar ist.
Endlich: Die Methode Listen verwenden
Nun sind wir soweit. Wenn der Benutzer auf den Button
cmdListen klickt, soll das Programm soweit vorbereitet werden,
dass ein andere Benutzer connecten kann. Stell dir das aber
nicht zu schwierig vor. Der folgende Code ist nötig:
Private Sub cmdListen_Click()
strNick = Left(txtName & Space(50), 50)
wsckChat.LocalPort = 12123
wsckChat.Listen
End Sub
Erklärungen: Die erste Zeile hat nur die Aufgabe, in der
Variable strNick den Nick zu speichern, der im Chat verwendet
wird.
Für den Chat absolut nötig, und deshalb auch
interessant, sind nur die beiden letzten Zeilen. Die
Eigenschaft LocalPort legt fest, auf welchem Port das Programm
laufen soll. Die Ports sind nötig, um verschiedenen
Netzwerk-Programme auf einem Rechner aufs mal laufen lassen zu
können. Oder hast du schon mal ernsthaft überlegt,
wie das Betriebssystem denn weiss, dass die reinkommenden
Daten jetzt für dem Browser und nicht dem Mail-Client
sind? Das geschieht durch die verschiedenen Ports (Beim
Web-Server z.B. meistens der Port 80)
Die Methode Listen sagt schliesslich, dass das Programm jetzt
bitte auf eine reinkommende Verbindung warten soll.
Wow, es nimmt einer Kontakt auf. Aber was jetzt?
Wenn wir jetzt die Methode Listen aufgerufen haben, kann man
noch nicht chatten. Schliesslich muss erst ein andere Rechner
Kontakt aufnehmen. Das geschieht über die Methode
Connect (kommt weiter unten). Wenn nun ein
Client Kontakt aufnimmt, feuert das Winsock-Control das Event
ConnectionRequest. Der Code sieht folgendermassen aus:
Private Sub wsckChat_ConnectionRequest(ByVal requestID As Long)
If wsckChat.State = sckListening Then
wsckChat.Close
wsckChat.Accept requestID
MsgBox "Es wurde eine Verbindung aufgenommen"
End If
End Sub
Erklärungen: Die IF-Abfrage dient dazu, Fehler zu
verhindern. Hinweise dazu findest du im kommentierten
Quellcode.
Wichtig ist die Methode Accept. Mit der wird eine reinkommende
Verbindung angenommen.
Was nützt mir ein Server ohne Client?
Die Antwort ist "Rein gar nix". Deshalb wollen wir
uns mal an den Client-Part machen. Da kommt die oft
erwähnte Methode Connect zum Einsatz.
Private Sub cmdConnect_Click()
Dim strRemoteComputer As String
strNick = Left(txtName & Space(50), 50)
strRemoteComputer = InputBox("RemoteHost:")
If Trim(strRemoteComputer) = "" Then Exit Sub
wsckChat.RemotePort = 12123
wsckChat.RemoteHost = strRemoteComputer
wsckChat.Connect
End Sub
Erklärungen: Um mit einem anderen PC zu connecten, muss
natürlich dessen IP bekannt sein. Die IP wird über die
InputBox eingegeben. Die Eigenschaft RemoteHost gibt an, zu
welchem Rechner verbunden werden soll. Danach muss dem
Winsock-Control bekanntgegeben werden, auf welchem Port es
verbinden soll. Die Eigenschaft RemotePort ist dafür
zuständig. Der Wert, welcher hier verwendet wird, muss
gleich sein, wie der Wert LocalPort, bei Listen.
Nachdem diese beiden Eigenschaften gesetzt wurden, wird die
Methode Connect aufgerufen. (Anmerkung: Die beiden Werten
könnten auch direkt der Methode übergeben werden. Das habe ich
hier aber aus Lernzwecken nicht so gelöst)
Das Programm ist jetzt soweit, dass zwei Rechner miteinander
Kontakt aufnehmen können. Allerdings werden noch keine
Nachrichten gesendet bzw. ausgewertet. Das folgt in den beiden
nächsten Abschnitten.
Nachrichten senden
Am Anfang dieses Tutorials habe ich die Sub Senden
vorgestellt. Diese soll nun verwendet werden. Folgender Code
ist für den Button cmdSend nötig.
Private Sub cmdSend_Click()
Dim strMessage As String
strMessage = strNick & _
txtNachricht.Text
Senden strMessage
AddMessage txtNachricht.Text, strNick
End Sub
Erklärungen: In der Sub wird erst die Nachricht
zusammengebaut. Danach wird sie versendet, und zuletzt wird
der Text noch im Chat-Fenster angezeigt. Übers Netzwerk
gesendet werden immer der Nick und die Nachricht.
Die Nachrichten empfangen
Die Nachrichten werden zwar versendet, aber sie werden noch
nicht angezeigt. So bringt uns der Chat natürlich nicht sehr
viel. Aber mit dem folgenden Code wird alles gut... ;-)
Private Sub wsckChat_DataArrival(ByVal bytesTotal As Long)
Dim strData As String
Dim strNick As String
Dim strMessage As String
wsckChat.GetData strData
strNick = Trim(Mid(strData, 1, 50))
strMessage = Mid(strData, 51)
AddMessage strMessage, strNick
End Sub
Erklärungen: Das Event DataArrival wird immer ausgelöst,
wenn Daten reinkommen. Hier müssen die Daten entgegengenommen
und verarbeitet werden.
Ins Programm rein bekommen wir die Daten mit der Methode
GetData. Dieser wird eine Variable übergeben, in welcher die
Daten gespeichert werden sollen. Dank dem Code strNick =
Left(txtName & Space(50), 50) weiter oben ist sichergestellt,
dass der Nick genau 50 Zeichen lang ist. Deshalb können wir
aus den reingekommenen Daten die ersten 50 Zeichen abschneiden
um den Nick zu erhalten. Ab Zeichen 51 ist dann die gesendete
Nachricht gespeichert. Deshalb die beiden Mid-Funktionen.
Mit einem Aufruf unserer Sub AddMessage wird die Nachricht ins
Chat-Fenster eingefügt.
Jetzt kannst du den Chat starten! Bereits können zwei Personen
miteinander chatten. Allerdings ist der Chat sehr primitiv.
Verbindung schliessen
Nach dem Motto "Einen hab' ich noch" zeige ich zum
Schluss, wie die Verbindung geschlossen wird:
Private Sub cmdCancel_Click()
If wsckChat.State <> sckClosed Then wsckChat.Close
End Sub
Erklärungen: Über die Eigenschaft State können
wir den Status des Winsock-Controls abfragen. Der Wert
sckClosed bedeutet soviel wie "Die Verbindung ist total
geschlossen". Durch die IF-Abfrage wird also
festgestellt, ob die Verbindung noch geöffnet ist. Wenn
ja, dann wird sie mit dem Aufruf der Methode Close
geschlossen.
Downloads
Zu diesem Artikel stehen zwei Downloads zur Verfügung:
Formular:
Das fertige Formular. Ohne Code
Ganzes
Projekt: Das gesamte Projekt. Mehr Code, als hier
erklärt.
Schlusswort und Ausblick
Ich hoffe, dieser Artikel hat dir gezeigt, wie einfach die Programmierung mit dem Winsock-Control ist. Falls du Fragen zu diesem Tutorial oder zur Winsock-Programmierung im Allgemeinen hast, so schreib mir doch einfach eine Mail.