| |
VB.NET - FortgeschritteneKommunikation zwischen Threads | | | Autor: RaMireZ | Datum: 30.08.08 04:05 |
| Hallo,
ich schreibe gerade eine Server-Client-Anwendung mit VB .Net 2008.
Ich habe früher mit VB6 gearbeitet und dabei das Winsck-Control benützt.
Da ich mich aber auch mal auf den .net krämpel einlassen will, hab ichs mal so probiert
(für mein Problem ist nur der SourceCode vom Server relevant):
Imports System.Net.Sockets
Public Class Form1
Dim sck_Server_TcpListener As TcpListener
Dim sck_ServerTcpClient As TcpClient
Dim sck_Server_NWS As NetworkStream
Dim bytes() As Byte
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles MyBase.Load
sck_Server_TcpListener = New TcpListener(System.Net.IPAddress.Parse(0), _
44000)
sck_Server_TcpListener.Start()
sck_Server_TcpListener.BeginAcceptTcpClient(AddressOf OnConnect, New _
Object)
End Sub
Private Sub OnConnect(ByVal data As System.IAsyncResult)
Log("connected")
sck_Server_TcpListener.EndAcceptTcpClient(data)
sck_ServerTcpClient.GetStream()
ReDim bytes(sck_ServerTcpClient.ReceiveBufferSize)
sck_Server_NWS.BeginRead(bytes, 0, CInt( _
sck_ServerTcpClient.ReceiveBufferSize), AddressOf OnDataArrival, New _
Object)
End Sub
Private Sub OnDataArrival(ByVal data As System.IAsyncResult)
Dim clientdata As String = System.Text.Encoding.ASCII.GetString(bytes)
ListView1.Items.Add(clientdata)
sck_Server_NWS.BeginRead(bytes, 0, CInt( _
sck_ServerTcpClient.ReceiveBufferSize), AddressOf OnDataArrival, New _
Object)
End Sub
Private Sub Log(ByVal Text As String)
ListView1.Items.Add(Text)
End Sub
End Class sobald also daten vom client kommen, sollen diese in die ListView1 geschrieben werden.
Jedoch gibt es eine Crossthreading-Fehlermeldung (an der Fettgedruckten Stelle). Das ist mir auch verständlich, weil der ConnectionThread ja nicht aufs ListView zugreifen darf, weil dieses nicht in diesem Thread erzeugt wurde. Aber wie löse ich das Problem jetzt? | |
Re: Kommunikation zwischen Threads | | | Autor: RaMireZ | Datum: 31.08.08 03:14 |
| na gut, du scheinst ahnung zu haben, dann stell ich gleich mal weitere fragen...es betrifft die kommunikation über den socket.
mein source code am server sieht so aus:
Public Class Form1
Dim sck_Server_TcpListener As TcpListener
Dim sck_ServerTcpClient As TcpClient
Dim sck_Server_NWS As NetworkStream
Dim bytes() As Byte
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles MyBase.Load
sck_Server_TcpListener = New TcpListener(System.Net.IPAddress.Parse(0), _
44000)
sck_Server_TcpListener.Start()
sck_Server_TcpListener.BeginAcceptTcpClient(AddressOf OnConnect, New _
Object)
End Sub
Private Sub OnConnect(ByVal data As System.IAsyncResult)
Log("connected")
sck_ServerTcpClient = sck_Server_TcpListener.EndAcceptTcpClient(data)
sck_Server_NWS = sck_ServerTcpClient.GetStream()
sck_Server_TcpListener.BeginAcceptTcpClient(AddressOf OnConnect, New _
Object)
ReDim bytes(sck_ServerTcpClient.ReceiveBufferSize)
sck_Server_NWS.BeginRead(bytes, 0, CInt( _
sck_ServerTcpClient.ReceiveBufferSize), AddressOf OnDataArrival, New _
Object)
End Sub
Private Sub OnDataArrival(ByVal data As System.IAsyncResult)
Dim clientdata As String = System.Text.Encoding.ASCII.GetString(bytes)
Log(clientdata)
Try
sck_Server_NWS.BeginRead(bytes, 0, CInt( _
sck_ServerTcpClient.ReceiveBufferSize), AddressOf OnDataArrival, _
New Object)
Catch ex As Exception
Log("Connection lost: " & ex.ToString)
sck_ServerTcpClient.Close()
sck_Server_NWS.Close()
End Try
End Sub
Private Sub Log(ByVal Text As String)
If Me.ListView1.InvokeRequired Then
Me.Invoke(New TextCallback(AddressOf SetListViewAdding), New Object( _
) {Text})
End If
End Sub
Private Sub SetListViewAdding(ByVal text As String)
ListView1.Items.Add(text)
End Sub
End Class wenn ich mich von 2 clients connecte, dann steht auch jeweils 1 mal connected da. das heisst, er peilt schon, dass dort 2 connections sind, aber übertragen kann ich nur noch daten mit dem zweiten client. kann mir da jemand helfen ? | |
Re: Kommunikation zwischen Threads | | | Autor: Drapondur | Datum: 31.08.08 16:02 |
| Hallo,
das liegt daran, dass Du für jeden Client, der sich verbindet nur eine einzige Variable (sck_ServerTcpClient) hast.
TcpListener.EndAcceptTcpClient gibt Dir jedoch pro Verbindung einen separaten, neuen TcpClient zurück. Statt Dir diesen Client in sck_ServerTcpClient zu merken (und somit den schon vorhandenen TcpClient zu überschreiben), speicherst Du Dir die Clients also besser in einer Collection - z.B. in einer List(Of TcpClient - ab.
Ciao
D. | |
Re: Kommunikation zwischen Threads | | | Autor: RaMireZ | Datum: 31.08.08 18:33 |
| ah ok danke für die info schonmal, leider sind diese collections von denen du sprichst absolutes neuland für mich, kannst du mir da helfen oder gute infoquellen nennen ? | |
Re: Kommunikation zwischen Threads | | | Autor: Drapondur | Datum: 31.08.08 19:42 |
| Hallo,
in der Klasse statt Dim sck_Server_NWS As NetworkStream Private _clients As New List(Of TcpClient) und in OnConnect nicht sck_ServerTcpClient = sck_Server_TcpListener.EndAcceptTcpClient(data) sondern 'TcpClient holen der zu dieser Verbindung gehört.
Dim client As TcpClient = sck_Server_TcpListener.EndAcceptTcpClient(data)
'In Liste merken
_clients.Add(client) Du kannst dann nicht mehr ein einziges Bytearray verwenden, sondern brauchst für jeden Client ein separates Bytearray.
Im letzten Argument von NetworkStream.BeginRead (state) übergibst Du dann beides, sowohl den Client als auch den dazugehörigen Byte-Buffer. Dies machst Du am einfachsten mit einer separaten Klasse z.B. Public Class ReadDataState
Public Sub New(ByVal client As TcpClient, ByVal bytes As Byte())
Me.Client = client
Me.ReceiveBuffer = bytes
End Sub
Public Client As TcpClient
Public ReceiveBuffer As Byte()
End Class Dieses Zustandsobjekt holst Du dir dann in OnDataArrival(data As IAsyncResult) aus der AsyncState-Eigenschaft von IAsyncResult wieder zurück.
Damit hast Du sowohl den aktuellen Client als auch den Buffer, der zu ihm gehört. Vom Client holst Du dir mit GetStream() wieder den NetworkStream.
Vo diesem rufst Du EndRead(data) auf. Somit erhälst Du dann nämlich die Anzahl tatächlch gelesener Bytes (es können ja auch weniger Bytes gelesen worden sein, als in den Buffer passen).
Wenn null Bytes gelesen wurden, heißt das, dass die Gegenstelle den Socket geschlossen hat. Dann oder wenn Networkstream.EndRead eine Exception schmeisst, schließt Du den Client und entfernst ihn aus der Liste aller Clients. | |
Re: Kommunikation zwischen Threads | | | Autor: RaMireZ | Datum: 31.08.08 19:56 |
| ohje, ich fürchte das habe ich nicht ganz verstanden...an welcher stelle soll dann ReadDataState genewt werden ? und welches zustandsobjekt soll durch die asyncstate-property von IAsyncResult gesetzt werden? | |
Re: Kommunikation zwischen Threads | | | Autor: Drapondur | Datum: 31.08.08 20:14 |
| Bevor Du das erste mal NetworkStream.BeginRead aufrufst, holst Du Dir ja den Client und erstellst ein Bytearray. Disese packst Du mit
Dim info as New ReadDataState(client, buffer) in ein neues Zustandsobjekt.
Networkstream.BeginRead rufst Du dann auf mit
Dim ns as NetworkStream = client.GetStream()
ns.BeginRead(info.ReceiveBuffer, 0, info.ReceiveBuffer.Length, AddressOf _
OnDataArrival, info) In OnDataArrival holst Du Dir eben dieses Zustandsobjekt mit
Dim info As ReadDataState = CType(data.AsyncState, ReadDataState) zurück. Dann hast Du sowohl Deinen Client als auch den Buffer.
Dim ns as NetworkStream = info.client.GetStream()
Dim numBytesRead = ns.EndRead(data)
'Hier testen, ob null Bytes gelesen wurden und Client schließen und aus
' _clients entfernen.
Dim message as String = SYstem.Text.Encoding.ASCII.GetString( _
info.ReceiveBuffer, numBytesRead) Diesen Code hier habe ich frei Hand geschrieben. Also sind Fehler noch weniger ausgeschlossen als sonst.
Ciao
D. | |
Re: Kommunikation zwischen Threads | | | Autor: RaMireZ | Datum: 01.09.08 01:07 |
| also ich hab das jetzt so versucht:
Imports System.Net.Sockets
Public Class Form1
Dim sck_Server_TcpListener As TcpListener
Private _clients As New List(Of TcpClient)
Dim sck_Server_NWS As NetworkStream
Dim bytes() As Byte
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles MyBase.Load
sck_Server_TcpListener = New TcpListener(System.Net.IPAddress.Parse(0), _
44000)
sck_Server_TcpListener.Start()
sck_Server_TcpListener.BeginAcceptTcpClient(AddressOf OnConnect, New _
Object)
End Sub
Private Sub OnConnect(ByVal data As System.IAsyncResult)
'TcpClient holen der zu dieser Verbindung gehört.
Dim client As TcpClient = sck_Server_TcpListener.EndAcceptTcpClient( _
data)
'In Liste merken
_clients.Add(client)
MsgBox("Connected")
Dim info As New ReadDataState(client, bytes)
'ReDim bytes(sck_ServerTcpClient.ReceiveBufferSize)
Dim ns As NetworkStream = client.GetStream()
ns.BeginRead(info.ReceiveBuffer, 0, info.ReceiveBuffer.Length, _
AddressOf _
OnDataArrival, info)
End Sub
Private Sub OnDataArrival(ByVal data As System.IAsyncResult)
Dim clientdata As String = System.Text.Encoding.ASCII.GetString(bytes)
Dim info As ReadDataState = CType(data.AsyncState, ReadDataState)
Dim ns As NetworkStream = info.Client.GetStream()
Dim numBytesRead = ns.EndRead(data)
Dim message As String = System.Text.Encoding.ASCII.GetString( _
info.ReceiveBuffer)
MsgBox(message)
ns.BeginRead(info.ReceiveBuffer, 0, info.ReceiveBuffer.Length, _
AddressOf _
OnDataArrival, info)
End Sub
End Class
Public Class ReadDataState
Public Sub New(ByVal client As TcpClient, ByVal bytes As Byte())
Me.Client = client
Me.ReceiveBuffer = bytes
End Sub
Public Client As TcpClient
Public ReceiveBuffer As Byte()
End Class das problem ist, dass wenn der client am server connected, gibt er noch die msgbox aus, bricht dann aber bei
ns.BeginRead(info.ReceiveBuffer, 0, info.ReceiveBuffer.Length, AddressOf _
OnDataArrival, info) in der OnConnect-Funktion ab. die fehlermeldung ist: Object reference not set to an instance of an object.
scheinbar wird bei dem GetStream() ein NullStream bzw irgendein nicht vorhandener stream zurückgegeben. weisst du weiter ? | |
Re: Kommunikation zwischen Threads | | | Autor: Drapondur | Datum: 01.09.08 01:27 |
| Hallo,
in OnConnect in der Zeile Dim bytes(client.ReceiveBufferSize - 1) As Byte ist bytes Nothing. Deswegen kommt in ns.BeginRead(info.ReceiveBuffer, 0, info.ReceiveBuffer.Length, _
AddressOf _
OnDataArrival, info) eine die Exception. Du hast also vergessen, das Byte-Array zu erzeugen.
Übrigens: Schmeisse auch gleich die erste ZeileDim clientdata As String = System.Text.Encoding.ASCII.GetString(bytes) in OnDataArrival raus bzw. entferne Dim bytes() As Byte aus Deiner Klasse.
Ciao
D. | |
Re: Kommunikation zwischen Threads | | | Autor: RaMireZ | Datum: 01.09.08 01:43 |
| aber das byte array ist ja leer, denn beim connecten vom client zum server schickt er ja noch nix. ich habe noch nichts gesendet. wie soll ich also ein bytearray "aus dem nichts" erzeugen und warum brauch ich das beim connecten? oO | |
Re: Kommunikation zwischen Threads | | | Autor: Drapondur | Datum: 01.09.08 01:49 |
| Das Byte-Array ist der Puffer, den Du bereitstellen musst, damit der TcpClient was zum füllen hat. Dim bytes(client.ReceiveBufferSize - 1) As Byte
Dim info As New ReadDataState(client, bytes)
Dim ns As NetworkStream = client.GetStream()
ns.BeginRead(info.ReceiveBuffer, 0, info.ReceiveBuffer.Length, _
AddressOf _
OnDataArrival, info) Ciao
D. | |
Re: Kommunikation zwischen Threads | | | Autor: RaMireZ | Datum: 01.09.08 02:08 |
| und das dann sowohl im OnConnect als auch im DataArrival?
ich glaube ich habe da was grundsätzlich nicht verstanden...ab wann wird dem NetworkStream (ns) denn die grösse des Puffers bekannt, die er braucht? nach deiner variante dimensionieren wir das bytesarray ja noch vor dem BeginRead. is die receivebuffersize denn nicht = 0? und nochmal der hinweis, das problem tritt beim connect auf, nicht beim empfangen, wenn der client was zum server hier geschickt hat ;) | |
Re: Kommunikation zwischen Threads | | | Autor: Drapondur | Datum: 01.09.08 02:26 |
| ab wann wird dem NetworkStream (ns) denn die grösse des Puffers bekannt, die er braucht?
Jeder Stream braucht einen Buffer, in den er während des Lesens etwas reinschreibt. Wieviel er lesen soll wird im dritten Argument von BeginRead angegeben werden.
is die receivebuffersize denn nicht = 0?
Einfach mal einen Haltpeunkt setzen und nachgucken...
Und ausprobieren, was ich Dir im letzten Posting geschrieben habe... | |
Re: Kommunikation zwischen Threads | | | Autor: Liam79Xbm | Datum: 12.10.20 14:02 |
| Ist es möglich, nur Runnables zu verwenden? Sollte Java Mehrfachvererbung zulassen? Wie kann ich viele verschiedene Threads einer anderen Klasse erstellen? | |
Re: Kommunikation zwischen Threads | | | Autor: Liam79Xbm | Datum: 30.10.20 12:29 |
| Diese coole neue und frische Webagentur aus der Schweiz hat alle unsere Content-Probleme gelöst. Wir möchten uns bedanken und wünschen Stammkunden für die Erstellung der Website, und sie werden die Ergebnisse und Ihre Einstellung zur Arbeit sehen. Es ist schön, mit Profis zu arbeiten. Wir bekamen einen qualitativ hochwertigen Job und sorgten dafür, dass die Wahl richtig war. Leute, viel Glück für euch und Wohlstand, neue Ideen und machbare Aufgaben, obwohl ihr hartnäckig seid, könnt ihr es tun!
Beitrag wurde zuletzt am 30.10.20 um 12:32:32 editiert. | |
| Sie sind nicht angemeldet! Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.
Einloggen | Neu registrieren |
|
|
Neu! sevDTA 3.0 Pro
SEPA mit Kontonummernprüfung
Erstellen von SEPA-Dateien mit integriertem BIC-Verzeichnis und Konto- nummern-Prüfverfahren, so dass ungültige Bankdaten bereits im Vorfeld ermittelt werden können. Weitere InfosTipp des Monats Access-Tools Vol.1
Über 400 MByte Inhalt
Mehr als 250 Access-Beispiele, 25 Add-Ins und ActiveX-Komponenten, 16 VB-Projekt inkl. Source, mehr als 320 Tipps & Tricks für Access und VB
Nur 24,95 EURWeitere Infos
|