Hi!
Ich bin jetzt erst dazu gekommen, das Problem weiter zu untersuchen. Folgendes konnte ich herausfinden: Der „Channel“ im Hintergrund scheint exakt nach 15 Sekunden beendet/pausiert zu werden und wird bei erneuter Verwendung neu aufgebaut/aktiviert. Dies scheint die erhöhte Latenz zu verursachen.
Hier nun der Code:
Der Contract:
\_
Public Interface [Interface]
\_
Function Counter() As System.Int32
End Interface
Meine Client-Klasse:
Public Class Client
Inherits ClientBase(Of [Interface])
Implements [Interface]
Public Sub New(ByVal Binding As Channels.Binding, ByVal RemoteAddress As EndpointAddress)
Call MyBase.New(Binding, RemoteAddress)
End Sub
Public Function Counter() As System.Int32 Implements [Interface].Counter
Return Me.Channel.Counter
End Function
End Class
Hier der Host für die Server-Seite:
Friend Class Host
Inherits Threading.Disposable
Private Host As ServiceHost
Public Sub New()
Call MyBase.New()
Call Trace.WriteLine("Starting Host.")
Dim Ex As System.Exception = Nothing
Try
Me.Host = New ServiceHost(GetType([Class]))
Dim Binding As New NetTcpBinding(SecurityMode.None)
Call Me.Host.AddServiceEndpoint(GetType([Interface]), Binding, "net.tcp://localhost:15781/LCS")
Call Me.Host.Open()
Catch iEx As Exception
Ex = iEx
Me.Host = Nothing
End Try
If Ex Is Nothing Then
Call Trace.WriteLine("Host is now running.")
Else
Call Me.Dispose()
Call Trace.WriteLine(Ex, "Starting Host")
Throw Ex
End If
End Sub
Protected Overrides Sub iiDispose()
If Me.Host IsNot Nothing Then
'Call Me.Host.Abort()
Call Me.Host.Close()
Me.Host = Nothing
End If
Call Trace.WriteLine("Disposing Host")
End Sub
End Class
Und hier die Server-Session:
\_
Friend Class [Class]
Implements [Interface]
Private ReadOnly LockObject As System.Object
Private iCounter As System.Int32
Public Sub New()
Me.LockObject = Core.Type.Format(Me.GetType)
Me.iCounter = 0
End Sub
Public Function Counter() As System.Int32 Implements [Interface].Counter
Dim Erg As System.Int32 = 0
SyncLock Me.LockObject
Me.iCounter += 1
Erg = Me.iCounter
End SyncLock
Return Erg
End Function
End Class
So starte ich den Proxy auf der Client-Seite:
Dim Binding As New NetTcpBinding(SecurityMode.None)
Dim Address As New EndpointAddress("net.tcp://localhost:15781/LCS")
Me.cmdStart.Enabled = False
Try
Me.Proxy = New LimitCheckService.Client(Binding, Address)
Call Me.Proxy.Open()
Me.cmdStop.Enabled = True
Catch Ex As System.Exception
Me.cmdStart.Enabled = True
End Try
Hier meine Test-Methode, die in einem BackGround-Worker läuft:
Dim Thread As Threading.Thread = Threading.Thread.Join("TestWorker")
Dim CurrentSleepDuration As System.Double = 14
Dim ts\_A As Core.TimeCode = Nothing
Dim Counter As System.Int32 = Nothing
Dim ts\_B As Core.TimeCode = Nothing
Dim LastResponseTime As Core.TimeCode = Time()
'Die ersten Aufrufe ungemessen ausführen, da diese westentlich langsamer laufen als die späteren.
For d As System.Int32 = 1 To 10
MyCounter += 1
Counter = Me.Proxy.Counter
Next d
Do
If Me.TestWorker.CancellationPending Then
e.Cancel = True
Exit Do
End If
MyCounter += 1
ts\_A = Time()
Counter = Me.Proxy.Counter
ts\_B = Time()
Call Trace.WriteLine(System.String.Format(" The Operation took {1} ms after waiting {2} s. MyCounter: {3} ServerCounter: {4}", Time, (Core.TimeCode.DeltaInSeconds(ts\_A, ts\_B) \* 1000).ToString("0.000"), Core.TimeCode.DeltaInSeconds(LastResponseTime, ts\_A).ToString("0.000"), MyCounter, Counter))
LastResponseTime = ts\_B
CurrentSleepDuration += 0.1
ts\_A = Time.AddSeconds(CurrentSleepDuration)
Do Until Time() \>= ts\_A
If Me.TestWorker.CancellationPending Then
e.Cancel = True
Exit Do
End If
Call Thread.Sleep(40)
Loop
Loop Until e.Cancel
Call Thread.Dispose()
Das ganze liefert diese Ausgabe:
The Operation took 0,109 ms after waiting 0,011 s. MyCounter: 11 ServerCounter: 11
The Operation took 0,419 ms after waiting 14,103 s. MyCounter: 12 ServerCounter: 12
The Operation took 0,376 ms after waiting 14,216 s. MyCounter: 13 ServerCounter: 13
The Operation took 0,372 ms after waiting 14,335 s. MyCounter: 14 ServerCounter: 14
The Operation took 0,380 ms after waiting 14,419 s. MyCounter: 15 ServerCounter: 15
The Operation took 0,376 ms after waiting 14,535 s. MyCounter: 16 ServerCounter: 16
The Operation took 0,441 ms after waiting 14,615 s. MyCounter: 17 ServerCounter: 17
The Operation took 0,462 ms after waiting 14,737 s. MyCounter: 18 ServerCounter: 18
The Operation took 0,448 ms after waiting 14,817 s. MyCounter: 19 ServerCounter: 19
The Operation took 0,376 ms after waiting 14,937 s. MyCounter: 20 ServerCounter: 20
The Operation took 340,351 ms after waiting 15,016 s. MyCounter: 21 ServerCounter: 21
Ab einer „Sendepause“ von 15 Sekunden, also einer Zeit in der in meinem Fall die Methode „Counter“ nicht aufgerufen wird, erhöht sich die Latenz. Und es sind immer 15 Sekunden. Es speilt keine Rolle, wieviele Aufrufe ich vorher durchführe o.ä. Ab 15 Sekunden Stille scheint WCF die Verbindung zu beenden oder zu pausieren.
Gibt es eine Option, mit der ich einstellen kann, wann der Channel pausiert werden soll? Besser noch, kann ich auf irgendeine Weise garantieren, dass alle Methoden aktiv bleiben, bis der Client beendet wird (also per Proxy.Close geschlossen wird)?
Die Anwendung die ich plane, besteht aus wenigen Clients (weniger als 20), diese halten die Verbindung aber evtl. über Tage hinweg. Im späteren produktiven Einsatz wird es nur selten Vorkommen, dass eine Methode länger als 15 Sekunden nicht benutzt wird, aber eine Latenz von 300 ms ist nicht akzeptabel. Eine Latzen von etwa 3 bis 5 ms wäre noch ok.
Schon jetzt besten dank für das Interesse.
Frederik.