4

I have created a web site (c# on Azure) which provides responses to a microcontroller (using a Texas Instruments CC3100 wifi chip).

The microcontroller has limited memory, and I would like to limit its buffer size to under 1000 bytes. I can use Transfer encoding Chunked (and it works), but I am struggling to work out how to set a maximum chunk size as it appears to be set "under the TCP/IP hood".

My current abbreviated code is as follows: -

    public class HITController : ApiController
{
    public async Task<HttpResponseMessage> Post()
    {
        byte[] RetContent = null;
        byte[] bytes = await Request.Content.ReadAsByteArrayAsync();//do stuff with incoming bytes
        RetContent = responseSelect(SiteSN, inData);//this gets a byte array of content to return
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        result.StatusCode = HttpStatusCode.OK;
        ByteArrayContent ResponseContent = new ByteArrayContent(RetContent);
       result.Content = ResponseContent;
       result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
       result.Headers.TransferEncodingChunked = true;
       return result;
   }
}

So far as I can see, there are no server or header settings which will limit chunk size. Is there some way of forcing a small chunk size (some kind of write followed by a flush maybe?).

Any help much appreciated.

ef9999
  • 41
  • 2
  • 3

1 Answers1

1

I am doing something similar on Azure. I have a Web API that I am calling from the CC3100 and when trying to download a file, I would like to limit the buffer size. I've implemented this in my controller, and when I look at the response with Wireshark when I call the controller from Postman, I noticed that well into the response, the size of the packets change from 1260 (which frames the desired buffer size of 1200 bytes), to 1514 bytes, which includes a 1200 byte sized chunk and a piece of the next chunk, which is not expected. Even weirder, the response syncs back up on 1260 byte sized packets for a few, then goes back to 1514 sized packets, and back to 1260. Now before someone suggests making the buffer bigger, realize that the receiver is an IoT device where memory (i.e. buffer space) is limited. By the way, thanks to https://stackoverflow.com/users/4391/david-kreps for the ChunkedStreamContent class. I modified it in an attempt to fix the buffer size at 1200.

    public async Task<HttpResponseMessage> Get(string model, string version)
    {
        try
        {
            // code that get vm removed

            var blobref = HttpUtility.UrlDecode(Path.GetFileName(vm.Url)) ;
            var container = Path.GetFileName(Path.GetDirectoryName(vm.Url));

            HttpContext.Current.Response.Buffer = false;    // turn off buffering
            HttpContext.Current.Response.BufferOutput = false;

            //var ret = await Task.Run(() => _blobService.FetchBlob(blobref, container));
            var resp = new HttpResponseMessage(HttpStatusCode.OK);
            resp.Headers.TransferEncodingChunked = true;
            //resp.Content = new ByteArrayContent(Encoding.UTF8.GetBytes(ret));
            var stream = await Task.Run(() => _blobService.FetchBlobToStream(blobref, container));
            stream.Position = 0;
            resp.Content = new ChunkedStreamContent(stream);

            return resp;

        }
        catch (Exception ex)
        {
            var resp = new HttpResponseMessage(HttpStatusCode.InternalServerError);
            var errmsg = "FirmwareUpdateController - Get - Error: " + ((ex.InnerException == null)
                ? ex.Message
                : ex.Message + " Inner Exception " + ex.InnerException.Message);
            _logger.Error(errmsg);

            resp.Content = new StringContent(errmsg);
            return resp;
        }
    }

public class ChunkedStreamContent : StreamContent
{
    public ChunkedStreamContent(Stream stream)
        : base(stream, 1200) { }

    protected override bool TryComputeLength(out long length)
    {
        length = 0L;
        return false;
    }
}

Here is a screen capture from Wireshark showing how the response packets drift,

Wireshark screen capture

Wireshark screen capture

Thanks

Mahendra Gunawardena
  • 1,956
  • 5
  • 26
  • 45
russd
  • 31
  • 4
  • TCP does not preserve messages at all. It presents a stream of bytes. This is expected and cannot reliably be avoided. The client must accept *any* receive size, including one byte at a time. – usr Jan 22 '16 at 23:45
  • That is true, which is why I'm surprised that the data is being reframed during the transfer. I would expect that by specifying chunked encoding and stream content with a buffer size of 1200, that the ASP.NET (IIS) would send the response in chunks based on the buffer size of the stream content. – russd Jan 25 '16 at 16:27
  • It probably does send those chunks but those are TCP-level chunks and not HTTP level chunks. HTTP chunks have HTTP syntax (the boundary marker or whatever it is called). There is no need for additional HTTP level chunks. – usr Jan 25 '16 at 16:29
  • Since TCP is a connection oriented protocol, the packets exchanged are chunks by definition. Since I'm using Web API, I am expecting that a chunked HTTP transfer would chunk the stream based on the size of the stream buffer (1200 bytes in this case). Since the receiver is not a conventional web browser but a device (TI CC3100 wifi module), I might actually be better off using websockets for this and, like you suggest, eliminate the HTTP chunking altogether. From the CC3100's perspective it's just a socket connection anyway so it may just work. – russd Jan 25 '16 at 21:46
  • Yeah, and the TCP packet level chunking is not observable by the client. You can't tell any read function to give you packets. They can give you any amount of data that is outstanding including less and including more than one packet. – usr Jan 26 '16 at 08:28