AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke C# Probleme mit Datenempfang über asynchronen Socket
Thema durchsuchen
Ansicht
Themen-Optionen

Probleme mit Datenempfang über asynchronen Socket

Ein Thema von Meflin · begonnen am 10. Sep 2010 · letzter Beitrag vom 11. Sep 2010
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Meflin
Meflin

Registriert seit: 21. Aug 2003
4.856 Beiträge
 
#1

Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 19:42
Hi,

ich versuche derzeit, einen asynchronen (TCP) Socket Client zu schreiben (C#). Der Server sendet serialisierte Objekte, wobei pro Objekt die ersten 4 Byte die länge des darauffolgenden Objekts verraten.

Der relevante Codeteil:
Code:
public class StateObject
{
    public Socket workSocket = null;
    public const int BufferSize = 2048;
    public byte[] buffer = new byte[BufferSize];
    public MemoryStream receivedObject = null;
    public bool lengthRead = false;
    public long dataLength = 0;
}

private void Receive()
{
    try
    {
        StateObject state = new StateObject();
        state.workSocket = client;

        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReceiveCallback), state);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

private void ReceiveCallback(IAsyncResult ar)
{
    try
    {
        StateObject state = (StateObject)ar.AsyncState;
        Socket client = state.workSocket;

        int bytesRead = client.EndReceive(ar);
        if (bytesRead > 0)
        {
            if (!state.lengthRead)
            {
                state.dataLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(state.buffer, 0));
                state.lengthRead = true;
                state.receivedObject = new MemoryStream(/*Convert.ToInt32(state.dataLength) + 4*/);
            }
            state.receivedObject.Write(state.buffer, 0, bytesRead);

            if (state.receivedObject.Length > state.dataLength)
            {
                Console.WriteLine("Receive done. Received {0} bytes, expected {1}.", state.receivedObject.Length, state.dataLength);
                Receive();
            }
            else
            {
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }
        }
        else
        {
            Console.WriteLine("Connection closed by server.");
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}
Allerdings funktioniert das ganze nicht so wie ich mir das denke. Im Moment müssten immer 4 Bytes mehr ankommen, als vermutet (da die Bytes für die Längenangabe mit in den Objektbuffer geschrieben werden).

Beispielausgabe des Programms:
Code:
Socket connected to xxx.
Sent 102 bytes to server.
Sent 48 bytes to server.
Receive done. Received 6836 bytes, expected 5714. <--
Receive done. Received 168 bytes, expected 164.
Sent 76 bytes to server.
Receive done. Received 128 bytes, expected 124.
Receive done. Received 240783 bytes, expected 240634. <--
Receive done. Received 110 bytes, expected 106.
Receive done. Received 125 bytes, expected 121.
Receive done. Received 138 bytes, expected 134.
Receive done. Received 121 bytes, expected 117.
Receive done. Received 118 bytes, expected 114.
Receive done. Received 134 bytes, expected 130.
Receive done. Received 129 bytes, expected 125.
Receive done. Received 296 bytes, expected 292.
Receive done. Received 242 bytes, expected 110. <--
Receive done. Received 142 bytes, expected 138.
Receive done. Received 296 bytes, expected 292.
Wie kann das nun sein?
  1. Die Dekodierung des Längenwertes ist falsch. Wieso ist sie aber dann fast immer richtig?
  2. Im Receivebuffer überlagern sich nicht zusammengehörige Objekte. Aber das darf doch garnicht sein . Das sollte doch eigentlich das Protokoll (TCP) für mich erledigen. Dann wäre die Frage, wann GENAU dieser Callback eigentlich aufgerufen wird. Definitives dazu konnte ich nicht finden
  3. ?
Ich hoffe, irgendjemand kann Licht in mein Dunkel bringen... Im Endeffekt will ich doch nur einfach pro empfangenem Objekt einen Callback aufrufen
Leo S.
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.639 Beiträge
 
#2

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 20:23
Schau dir mal InternetPack an (opensource Library für .NET von RemObjects). Da ist das Handling von so Sachen einfacher.
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Benutzerbild von Meflin
Meflin

Registriert seit: 21. Aug 2003
4.856 Beiträge
 
#3

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 20:59
Schau dir mal InternetPack an (opensource Library für .NET von RemObjects). Da ist das Handling von so Sachen einfacher.
Auf meiner erfolglosen Suche nach brauchbaren Wrappern habe ich mir das bereits angeguckt. Die Informationen im Wiki dazu sind allerdings äußerst spärlich. Außer dass da die selben Methoden (BeginXXX und EndXXX) in Grün existieren, konnte ich nichts herausfinden.

Und damit habe ich das als nicht-Vereinfachung auch wieder verworfen...
Leo S.
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 16. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#4

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 22:49
Mal so ganz grundsätzlich:
Auf der Empfangsseite darfst du keinerlei Erwartungen haben, wieviele Bytes auf einen Rutsch eintreffen.
Stell' Dir einfach vor, ein Zufallsgenerator würde dem Empfänger die Bytes zuteilen.
Angenommen der Sender schickt 4 Bytes Länge + 100 Bytes Objektdaten.
Am Empfänger könnten zuerst 15 Bytes und dann 89 Bytes eintreffen.
Oder auch 3 Bytes, 64 Bytes und dann 85 Bytes.
(das wären in der Summe mehr als 104 Bytes denn ein Teil der nächsten Message hängt noch hinten dran)

Daher muss der empfangene Datenblock an einen Puffer angehängt werden.
Danach wird untersucht, ob eine vollständige Message im Puffer enthalten ist.
Falls ja, die Message aus dem Puffer ausschneiden, Message verarbeiten und schauen ob noch eine weitere Message im Puffer ist.
  Mit Zitat antworten Zitat
Benutzerbild von Meflin
Meflin

Registriert seit: 21. Aug 2003
4.856 Beiträge
 
#5

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 23:31
Auf der Empfangsseite darfst du keinerlei Erwartungen haben, wieviele Bytes auf einen Rutsch eintreffen.
Stell' Dir einfach vor, ein Zufallsgenerator würde dem Empfänger die Bytes zuteilen.
Das ist mir durchaus bewusst - auf der Netzwerkebene. ABER: genau davon sollte doch ein TCP-Socket bereits abstrahieren. Müsste ich die TCP Segmente manuell wieder zusammensetzen, könnte ich mir ja das Protokoll sparen - oder ist dies bereits eine Fehlannahme

Und so viel ist sicher: Der Socket-Callback wird auch nicht per Segment aufgerufen. Leider halt auch nicht per Paket, was logischerweise durch dieses dämliche Buffergehandhabe auch garnicht möglich wäre (wegen potentiell größerer Pakete).

so ganz schlau werde ich aus der Sache noch nicht...
Leo S.
  Mit Zitat antworten Zitat
Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#6

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 00:51
Liest Du hier nicht ab dem falschen offset das Objekt?
Code:
state.receivedObject.Write(state.buffer, 0, bytesRead);
state.buffer ist ja ein byte[] array und kein Stream, der die zuletzt gelesenen Position behält. Würde zumindest auf den ersten Blick die Abweichungen um 4 Byte erklären.

state und damit state.lengthRead ist auch lokal innerhalb des Handlers deklariert und somit bei jedem Aufruf erst einmal false. Passt nur, wenn der Handler pro Objekt-Abruf nicht mehr als einmal aufgerufen wird (kenne aber die Logik des Handlers nicht)

Geändert von Satty67 (11. Sep 2010 um 01:06 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Meflin
Meflin

Registriert seit: 21. Aug 2003
4.856 Beiträge
 
#7

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 01:03
Liest Du hier nicht ab dem falschen offset das Objekt?
Ich denke nicht. Alles was im Buffer steht wird ja ausgelesen und der nächste Callback durch das aufrufen von BeginReceive ausgelöst (bessergesagt ermöglicht), womit auch von vorne in den Buffer geschrieben wird.

Zitat:
Würde zumindest auf den ersten Blick die Abweichungen um 4 Byte erklären.
Die 4 Byte Abweichung ist richtig. Problematisch sind die <-- markierten Stellen
Leo S.

Geändert von Meflin (11. Sep 2010 um 01:11 Uhr)
  Mit Zitat antworten Zitat
Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#8

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 01:09
Ja aber beim ersten Aufruf des Handlers pro Objekt, gehören die ersten 4 Byte ja nicht zum Objekt. Werden aber auch da mit in den Stream geschrieben.

Kommt der zweite Aufruf beim gleichen Objekt, werden wieder 4 Byte als Längen Angabe ermittelt, obwohl diesmal alle Bytes zum Objekt gehören (weil state lokal definiert ist).

€: Ok... rekusrsiver Aufruf mit Übergabe des alten state. Der erste Teil sollte aber trotzdem wie beschrieben falsch alufen.

Geändert von Satty67 (11. Sep 2010 um 01:19 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Meflin
Meflin

Registriert seit: 21. Aug 2003
4.856 Beiträge
 
#9

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 01:19
Kommt der zweite Aufruf beim gleichen Objekt, werden wieder 4 Byte als Längen Angabe ermittelt, obwohl diesmal alle Bytes zum Objekt gehören (weil state lokal definiert ist).
Der state wird ja beim Aufruf von Receive erstellt. Das wird aber pro Objekt nur einmal aufgerufen. Was öfter aufgerufen wird ist ReceiveCallback, aber da wird der State ja nur wiederverwendet. Ich bin mir relativ sicher, dass das nicht das problem ist. Andernfalls würde ja mit jedem ReceiveCallback auch ein neuer length-Wert gelesen, und das wäre mit relativ hoher Wahrscheinlichkeit eine sehr große Zahl (kaum aufeinanderfolgende Nullbytes in den Daten). Damit würde auch das Console.Log sehr viel später erreicht.

Zum Thema 4-Byte-Differenz: siehe mein Edit im vorigen Beitrag. Das stimmt so, ist nur ne Ausgabesache
Leo S.
  Mit Zitat antworten Zitat
Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#10

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 01:23
Ja, OK

War wohl zuviel information im ersten Post. Hatte auch zu spät gesehen, dass state als Parameter wiederverwendet wird und mich an der wenig relevanten 4-Byte Abweichung festgekrallt.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz