• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook page for updates, we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.) When you see an Incapsula error, you know we are in the process of migration.

[C#] Begin/EndReceive - how do I read large data?

Newbie Spellweaver
Joined
Feb 24, 2011
Messages
60
Reaction score
5
When reading data in chunks of say, 1024, how do I continue to read from a socket that receives a message bigger than 1024 bytes until there is no data left? Should I just use BeginReceive to read a packet's length prefix only, and then once that is retrieved, use Receive() (in the async thread) to read the rest of the packet? Or is there another way?

PHP:
public class StateObject
{
    public Socket workSocket = null;
    public const int BUFFER_SIZE = 1024;
    public byte[] buffer = new byte[BUFFER_SIZE];
    public StringBuilder sb = new StringBuilder();
}

public static void Read_Callback(IAsyncResult ar)
{
    StateObject so = (StateObject) ar.AsyncState;
    Socket s = so.workSocket;

    int read = s.EndReceive(ar);

    if (read > 0) 
    {
        so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));

        if (read == StateObject.BUFFER_SIZE)
        {
                s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0, 
                                new AyncCallback(Async_Send_Receive.Read_Callback), so);
                return;
        }
    }

    if (so.sb.Length > 0)
    {
        //All of the data has been read, so displays it to the console
        string strContent;
        strContent = so.sb.ToString();
        Console.WriteLine(String.Format("Read {0} byte from socket" + 
        "data = {1} ", strContent.Length, strContent));
    }
    s.Close();
}

Now this corrected works fine most of the time, but it fails when the packet's size is a multiple of the buffer. The reason for this is if the buffer gets filled on a read it is assumed there is more data; but the same problem happens as before. A 2 byte buffer, for exmaple, gets filled twice on a 4 byte packet, and assumes there is more data. It then blocks because there is nothing left to read. The problem is that the receive function doesn't know when the end of the packet is.

This got me thinking to two possible solutions: I could either have an end-of-packet delimiter or I could read the packet header to find the length and then receive exactly that amount (as I originally suggested).

There's problems with each of these, though. I don't like the idea of using a delimiter, as a user could somehow work that into a packet in an input string from the app and screw it up. It also just seems kinda sloppy to me.

The length header sounds ok, but I'm planning on using protocol buffers - I don't know the format of the data. Is there a length header? How many bytes is it? Would this be something I implement myself? Etc..

What should I do?
 
Joined
Jun 8, 2007
Messages
1,985
Reaction score
490
I don't know any C#, but you can try this:

Get the bytes of the data (~length~) with the client using a delimiter (since the length is going to be integers, the delimiter can be almost anything), send that length to server, then send the data- after the server knows the length.

You can measure the bytes on the server after the data has been received, and compare it with what was sent from the client. If the numbers are the same (and assuming length was sent correctly), you just got every byte like a charm.
 
Last edited:
Experienced Elementalist
Joined
Apr 12, 2009
Messages
241
Reaction score
32
I generally read from sockets and write the data into a MemoryBuffer... it keeps expanding until you've got enough data... at which time you process it, and clear the MemoryBuffer
 
Back
Top