Clientwebsocket Verbindung bricht ständig ab

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Facebamm.

    Clientwebsocket Verbindung bricht ständig ab

    Wie der Titel schon beschreibt bricht die Verbindung ständig ab.
    Dies ist vom Intervall abhängig, mit welchem ich

    Quellcode

    1. SendAsync()
    , bzw.

    Quellcode

    1. ReceiveAsync()
    aufrufe...
    Etwas zu schnell, und der WebsocketState geht auf 4(CloseReceived), bzw 6(Aborted).
    Ich kenne mich offensichtlich nicht wirklich mit Websockets aus, wollte aber fragen ob jemand eventuell den Grund dafür kennt.
    Bei einem Kollegen funktioniert das in einer anderen Sprache ohne Probleme.

    Hier der Connect:

    VB.NET-Quellcode

    1. Private Async Function Connect() As Task(Of Integer)
    2. ws = New System.Net.WebSockets.ClientWebSocket
    3. ServicePointManager.ServerCertificateValidationCallback = Function(s, c, h, d) True
    4. ws.Options.AddSubProtocol("graphql-transport-ws")
    5. Try
    6. Await ws.ConnectAsync(New Uri("wss://URL"), Nothing)
    7. If (ws.State = WebSockets.WebSocketState.Open) Then
    8. Await ws.SendAsync(New ArraySegment(Of Byte)(System.Text.Encoding.UTF8.GetBytes("{ConnectString}")), WebSockets.WebSocketMessageType.Text, True, Nothing)
    9. Dim bytes(4096) As Byte
    10. Dim answ = New ArraySegment(Of Byte)(bytes)
    11. Await ws.ReceiveAsync(answ, Nothing)
    12. RichTextBox1.Text += vbNewLine + "answer:" + System.Text.Encoding.UTF8.GetString(answ.Array)
    13. Return 0
    14. Else
    15. Return 1
    16. End If
    17. Catch ex As WebSockets.WebSocketException
    18. RichTextBox1.Invoke(Sub()
    19. RichTextBox1.Text += ex.Message
    20. End Sub)
    21. Return 1
    22. End Try
    23. End Function


    Und der die Methode mit der ich in einem bestimmten Intervall SendAsync() und ReceiveAsync() aufrufen möchte (Fast identisch, aber der vollständigkeit halber hier drin):

    VB.NET-Quellcode

    1. Private Async Function SendReceive() As Task
    2. Try
    3. If (ws.State = WebSockets.WebSocketState.Open) Then
    4. Await ws.SendAsync(New ArraySegment(Of Byte)(System.Text.Encoding.UTF8.GetBytes("{SendString}")), WebSockets.WebSocketMessageType.Text, True, Nothing)
    5. Dim bytes(4096) As Byte
    6. Dim answ = New ArraySegment(Of Byte)(bytes)
    7. Await ws.ReceiveAsync(answ, Nothing)
    8. RichTextBox1.Text += vbNewLine + "answer:" + System.Text.Encoding.UTF8.GetString(answ.Array)
    9. counter += 1
    10. Label2.Invoke(Sub()
    11. Label2.Text = CStr(counter)
    12. End Sub)
    13. ElseIf (ws.State = WebSockets.WebSocketState.CloseReceived) Then
    14. 'Await Connect()
    15. ElseIf (ws.State = WebSockets.WebSocketState.Aborted) Then
    16. 'Await Connect()
    17. End If
    18. Catch ex As WebSockets.WebSocketException
    19. RichTextBox1.Text = ex.InnerException.Message + vbNewLine + CStr(ws.State)
    20. End Try
    21. End Function


    Ich hoffe ich mache einfach nur irgendetwas falsch^^..

    *Topic verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Dann drück ich es einmal anders aus. Wenn du dem Compiler sagst: die Funktion Connect gibt ein Task(Of Integer) zurück, tatsächlich gibt diese aber einen Integer zurück, fällt dir das irgendwann auf die Füße. Gleiches gilt für die Funktion SendReceive, wenn du dem Compiler sagst: die Funktion gibt einen Task zurück und tatsächlich hat diese überhaupt keinen Rückgabewert, fällt es dir irgendwann auf die Füße.
    Apparently, I was hitting an HTTP.SYS low speed connection attack countermeasure, as roughly described in KB 3137046 (https://support.microsoft.com/en-us/help/3137046/http-sys-forcibly-disconnects-http-bindings-for-wcf-self-hosted-servic):
    By default, Http.sys considers any speed rate of less than 150 bytes per second as a potential low speed connection attack, and it drops the TCP connection to release the resource.
    When HTTP.SYS does that, there is a trace entry in the log at %windir%\System32\LogFiles\HTTPERR
    Switching it off was simple from code:
    httpListener.TimeoutManager.MinSendBytesPerSecond = UInt32.MaxValue;

    War die Lösung in diesem Post: .NET WebSocket closing for no apparent reason

    Wenn du also zu langsam schickst, dann wird das wohl als Angriff gewertet und die Verbindung wird abgebrochen. Das musst du dann vermeiden.
    Du liest nicht bis zum ende.

    VB.NET-Quellcode

    1. Dim bytes(4096) As Byte
    2. Dim answ = New ArraySegment(Of Byte)(bytes)
    3. Await ws.ReceiveAsync(answ, Nothing)
    4. RichTextBox1.Text += vbNewLine + "answer:" + System.Text.Encoding.UTF8.GetString(answ.Array)

    Was passiert wenn es mehr als 4096 bytes sind? (ws.EndOfMessage)

    zu dem ich immer ein CancellationToken rein geben würde.
    Da kannst du default parameter setzen mit dem default Wert


    stackoverflow.com/questions/46…ebsockets-have-heartbeats
    Schau wir doch mal was die Docu zu ReceiveAsync sagt: docs.microsoft.com/en-us/dotne…receiveasync?view=net-6.0 (hier könnten abweichungen statt finden, da du .NET (FX) 4.5–4.8 nutzt .... btw. weißt du wofür das steht?)

    ReceiveAsync hat zwei Overloads:
    1: ReceiveAsync(ArraySegment<Byte>, CancellationToken)
    2: ReceiveAsync(Memory<Byte>, CancellationToken)

    da du im quellcode Dim answ = New ArraySegment(Of Byte)(bytes) nutzt, fällt die 2 überladung weg.

    Visual Basic-Quellcode

    1. Public Overrides Function ReceiveAsync (buffer As ArraySegment(Of Byte), cancellationToken As CancellationToken) As Task(Of WebSocketReceiveResult)


    Wie du sehen kannst gibt uns die Methode ein Task(of WebSocketReceiveResult).
    Was ist WebSocketReceiveResult bzw. welche methode und eigenschaften hat das? (docs.microsoft.com/en-us/dotne…eceiveresult?view=net-6.0)

    Visual Basic-Quellcode

    1. ​Public Class WebSocketReceiveResult


    Beim genauer hinschau in die Doku findest du die Eigenschaft:
    EndOfMessage, welche "Indicates whether the message has been received completely." - hier rüber erfährst du ob du am ende deiner Message bist.
    Nehmen wir den Fall an Nachricht ist länger als 4096 zb. >5000 bytes lang

    Dann würdest du 1x komplett den Buffer zwischen Speicher und nochmal lesen
    Jetzt bekommst du EndOfMessage := true, die frage nun ist aber wie viele Bytes gelesen wurden, dazu hast du die mgl. die Eigenschaft Count abzufragen, denn die Liefert dir zurück, wie viel Bytes gelesen wurden vom ReceiveAsync.

    Wie geht das mit dem CancellationToken ... naja zum einen kannst du Standart-Parameter(default) setzten d.h. wenn du diesen Parameter nicht mit angibst, dann bekommt der Parameter den vordefinierten Wert.

    Bsp: Sub BlaAsync(ByVal val As String, Optional ByVal ct As CancellationToken = Nothing) ... hier solltest du aber immer ein ct setzen.

    Quellcode

    1. Await BlaAsync("blablabla")

    Hier würde der Parameter ct Nothing sein

    Quellcode

    1. CancellationTokenSource cts
    2. CancellationToken ct = cts.Token
    3. Await BlaAsync("blablabla", ct)

    Hier hat der Parameter ct der wert vom cts.Token.

    "nicerdicer" schrieb:

    Da hast du wohl recht, das war mir nicht bewusst, danke.

    Dann hast du sicherlich auch verstanden das auf die Methode SendReceive nicht gewartet werden kann. D.H. wenn du irgendwo await SendReceive geschrieben hast kann nicht darauf gewartet werden.

    Fakiz schrieb:

    Dann hast du sicherlich auch verstanden das auf die Methode SendReceive nicht gewartet werden kann. D.H. wenn du irgendwo await SendReceive geschrieben hast kann nicht darauf gewartet werden.


    Stimmt, es muss nämlich gewartet werden, denn im inneren hat er Await ws.SendAsync und Await ws.ReceiveAsync