Einzelnen Beitrag anzeigen

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