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, 18: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)
Online

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

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 19: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, 19: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 Meflin
Meflin

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

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 11:24
Schau dir mal InternetPack an (opensource Library für .NET von RemObjects). Da ist das Handling von so Sachen einfacher.
habe jetzt in den Newsgroups auch noch das hier gefunden:
Zitat:
Internet Pack is designed based on the synchronous communication model -
where your code will block until it receives data and then handles it -
rather then asynchronously waiting for events. to get a line of data, simply
call the Readline() method of your connection, it will block and receive a
full line of text, terminated by a (CR)LF. (or it will timeout, if timeuts
are configured to apply)
Klingt jetzt nicht so direkt nach der Richtung, in die ich gehen möchte (Und Line Based bringt mir auch absolut nichts, da es das nicht ist)
Leo S.
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

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

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 12:08
Müsste ich die TCP Segmente manuell wieder zusammensetzen, könnte ich mir ja das Protokoll sparen - oder ist dies bereits eine Fehlannahme
Der TCP Stack sorgt dafür, dass fehlende Pakete und Pakete mit falscher Prüfsumme wiederholt werden.
Ausserdem wird dafür Sorge getragen, dass die Pakete in korrekter Reihenfolge beim Empfänger ankommen.

Wie gross die Pakete sind kann weder der Sender noch der Empfänger wirklich steuern.
Die IP-Pakete können unterwegs im Netzwerk z.B. auch gesplittet werden. IP-Fragmentierung

Es ist nur sicher, dass der Datenstrom beim Empfänger so austritt, wie beim Sender eingespeist wurde.
Der Sender verschickt aber einzelne Messages (4 Bytes Länge + Nutzdaten) und der Empfänger muss diese wieder auftrennen.
Das nennt man Message Framing.
Ohne korrektes Message Framing wird die Datenübertragung über ein reales Netzwerk nie funktionieren.

Ich würde mir dafür eine eigene Klasse schreiben.
Die Daten werden wie in einer Queue gesammelt und immer wenn eine vollständige Message beisammen ist,
wird ein Event ausgelöst.
Die Nutzdaten werden über einen Parameter des Events weitergegeben.
  Mit Zitat antworten Zitat
Benutzerbild von Meflin
Meflin

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

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 16:56
Ich würde mir dafür eine eigene Klasse schreiben.
Die Daten werden wie in einer Queue gesammelt und immer wenn eine vollständige Message beisammen ist,
wird ein Event ausgelöst.
Die Nutzdaten werden über einen Parameter des Events weitergegeben.
Danke für deine Ausführungen, genau so habe ich es jetzt gelöst, und nach ersten Tests scheint alles so weit zu klappen
Leo S.
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

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

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 21: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
 
#8

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 22: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
 
#9

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 10. Sep 2010, 23: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 00:06 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Meflin
Meflin

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

AW: Probleme mit Datenempfang über asynchronen Socket

  Alt 11. Sep 2010, 00: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 00:11 Uhr)
  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 08:13 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