简体   繁体   中英

C# Socket Receive: Taking in data until buffer is full dilemma

Here is my code I'm having an issue with:

// read the file in chunks of 5KB
var buffer = new byte[1024*5];
int bytesRead = 0;
do
{
    bytesRead = host.Receive(buffer, buffer.Length, 0);
    output.Write(buffer, 0, bytesRead);
}
while (bytesRead == buffer.Length);

So here's my problem: I want to read in data as long as the buffer is full. However, even if there is more data, the buffer isn't guaranteed to be filled when sending. This causes the Receive to prematurely exit. If I change the while condition to bytesRead > 0 then it reaches the end of data and Receive blocks until more data is available (which it won't be). How do I solve this?

I think you need to think about how the protocol works and make a more robust solution. Either you go with blocking and then you could either wait until you have no more data to read and then do something else and read again when you know you have more data to read.

Or you add threading and have a seperate thread that just reads and then it doesn't matter if it blocks since it will be on a seperate thread.

Another solution that might be simpler is to use asynchronous reads.

You can read more about it here: https://msdn.microsoft.com/en-us/library/bbx2eya8(v=vs.110).aspx

A simple example from the site above is to start with the read:

private static void Receive(Socket client) {
    try {
        // Create the state object.
        StateObject state = new StateObject();
        state.workSocket = client;

        // Begin receiving the data from the remote device.
        client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReceiveCallback), state);
    } catch (Exception e) {
        Console.WriteLine(e.ToString());
    }
}

Then you will get a callback to ReceiveCallback when there is data to be handled:

private static void ReceiveCallback( IAsyncResult ar ) {
    try {
        // Retrieve the state object and the client socket 
        // from the asynchronous state object.
        StateObject state = (StateObject) ar.AsyncState;
        Socket client = state.workSocket;
        // Read data from the remote device.
        int bytesRead = client.EndReceive(ar);
        if (bytesRead > 0) {
            // There might be more data, so store the data received so far.
            state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));
                //  Get the rest of the data.
            client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
                new AsyncCallback(ReceiveCallback), state);
        } else {
            // All the data has arrived; put it in response.
            if (state.sb.Length > 1) {
                response = state.sb.ToString();
            }
            // Signal that all bytes have been received.
            receiveDone.Set();
        }
    } catch (Exception e) {
        Console.WriteLine(e.ToString());
    }
}

I hope this works if not we need to know more about what protocol you use and if there is some reason you need blocking reads so we can give more specific information and help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM