views:

101

answers:

2

I've implemented a async funtion in order to read large socket data, mostly files will be transferred. Code is based on this question:

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();
}

After all of the data has been captured in the stringbuilder, I decrypt it and convert the base64 string to a file using another method. There will be multiple socket receiving\sending files so every workersocket has an ID.

Now here's the case; I want some status on the receiving file. For example a progress bar showing how much is received and the total amount to be received. The Read_Callback method uses a recursive call in order to get all the data from the socket, which prevents me from getting the total amount to be received. Does anyone know how to get the total amount the socket has to receive? Or is my only option to send the size fixed to the listener before transferring the data?

As mentioned before, my stateobject class contains an ID for identifying the socket which the data is for. Upon first connection, the program stores the connection and received info in an arraylist.

In order to get the amount of bytes already read, I have to report the status to one of the initiated worker classes stored in the arraylist. If I want to do this during the recursive call, how will I perform this without losing performance when receiving data?

As last, which buffer size should be used? should this be the MTU of tcp which is 1500 bytes in most cases?

Note: I'm fairly new to C# programming, feel free to comment on bad practices or anything else.

+1  A: 

I would suggest sending the total file size as the first step in your communication, before sending along the actual file. For example your StateObject class could have an additional property that holds the total size of the thing your transmitting, then in a different thread (the UI thread) you can create a progress bar and report based of the total transmitted vs the total size of the file as a percentage or whatever you like. Just track how much data has been transmitted as it occurs and update your object appropriately as it does so.

Capital G
Thanks, will think about this further.
Mengo
A: 

In addition to CG's answer, I would also skip the stringbuilder and use something like:

        FileStream fs = File.OpenRead(filePath);
        Byte[] bytes = new Byte[fs.Length];
        fs.Read(bytes, 0, Convert.ToInt32(fs.Length));
        fs.Close();
Jess