vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Top-Preis! AP-Access-Tools-CD Volume 1  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück

 Sie sind aktuell nicht angemeldet.Funktionen: Einloggen  |  Neu registrieren  |  Suchen

VB.NET - Fortgeschrittene
Kommunikation 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?
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Kommunikation zwischen Threads 
Autor: ModeratorRalf Ehlert (Moderator)
Datum: 30.08.08 08:39

Du musst über die Invoke()-Methode des Steuerelementes in den UI-Thread wechseln. Gibt im Forum dazu einiges, hier aber der Teil, den du hinzufügen musst bzw. modifizieren musst:
Private Delegate Sub LogDelegate(ByVal text As String)
 
Private Sub Log(ByVal text As String)
  If ListView1.IsInvokeRequeiered() Then
    ListView1.Invoke(New LogDelegate(AddressOf Log), text)
  Else
    ListView1.Items.Add(text)
  End If
End Sub

Ralf

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

Re: Kommunikation zwischen Threads 
Autor: ModeratorRalf Ehlert (Moderator)
Datum: 30.08.08 08:51

Es gibt auch andere Wege der Kommunikation: Pipes (ab .NET 3.5 im Framework enthalten im Namespace System.IO.Pipes), IPC (Interprocess Communication; ab .NET 2.0), was .NET Remoting bedingt oder wenn du nicht direkt auf Byteebene arbeiten willst, sondern eher auf Nachrichtenebene, kann man auch einen WCF-Service bauen (ab .NET 3.0).

Ist nur, damit du siehst, was alles möglich ist. Am effektivsten von der Geschwindigkeit her ist IPC, denn bei den Sockets musst du zweimal durch den ganzen Netzwerkstack und das ist schon bissle was

Ralf

Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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 ?
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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 ?
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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?
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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 ?
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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 Zeile
Dim clientdata As String = System.Text.Encoding.ASCII.GetString(bytes)
in OnDataArrival raus bzw. entferne Dim bytes() As Byte aus Deiner Klasse.

Ciao
D.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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 ;)
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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...
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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?
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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.
Themenbaum einblendenGesamtübersicht  |  Zum Thema  |  Suchen

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

Funktionen:  Zum Thema  |  GesamtübersichtSuchen 

nach obenzurück
 
   

Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel