![]() |
Probleme mit Datenempfang über asynchronen Socket
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:
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).
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()); } } Beispielausgabe des Programms:
Code:
Wie kann das nun sein?
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.
|
AW: Probleme mit Datenempfang über asynchronen Socket
Schau dir mal InternetPack an (opensource Library für .NET von RemObjects). Da ist das Handling von so Sachen einfacher.
|
AW: Probleme mit Datenempfang über asynchronen Socket
Zitat:
Und damit habe ich das als nicht-Vereinfachung auch wieder verworfen... |
AW: Probleme mit Datenempfang über asynchronen Socket
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. |
AW: Probleme mit Datenempfang über asynchronen Socket
Zitat:
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... |
AW: Probleme mit Datenempfang über asynchronen Socket
Liest Du hier nicht ab dem falschen offset das Objekt?
Code:
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.receivedObject.Write(state.buffer, 0, bytesRead);
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) |
AW: Probleme mit Datenempfang über asynchronen Socket
Zitat:
Zitat:
|
AW: Probleme mit Datenempfang über asynchronen Socket
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. |
AW: Probleme mit Datenempfang über asynchronen Socket
Zitat:
Zum Thema 4-Byte-Differenz: siehe mein Edit im vorigen Beitrag. Das stimmt so, ist nur ne Ausgabesache :) |
AW: Probleme mit Datenempfang über asynchronen Socket
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. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz