Home > Mobile >  NetworkStream.read taking 2 seconds to read data from stream (TCP C#)
NetworkStream.read taking 2 seconds to read data from stream (TCP C#)

Time:05-06

I have a TCP request response model in C# where I am communicating with a server. Once the server has written data to the stream, I am reading that data. But stream.read is taking 2 seconds to read the data. I need to send an explicit acknowledgement to the server, within 2 seconds but am unable to do so because of the time taken to read the data. Below is my code to read data:

            byte[] resp = new byte[100000];
            var memoryStream = new MemoryStream();
            int bytes;

            String timeStamp = GetTimestamp(DateTime.Now);
            Console.WriteLine("Before reading data: ");
            Console.WriteLine(timeStamp);

            do
            {
                bytes = stream.Read(resp, 0, resp.Length);
                memoryStream.Write(resp, 0, bytes);
                               
            }
            while (bytes > 0);

            timeStamp = GetTimestamp(DateTime.Now);
            Console.WriteLine("After reading data: ");
            Console.WriteLine(timeStamp);

            
            GenerateAcknowledgemnt(stream);


            timeStamp = GetTimestamp(DateTime.Now);
            Console.WriteLine("After sending ack: ");
            Console.WriteLine(timeStamp);


Below are the timestamps read, in the format yyyyMMddHHmmssff:

Before reading data: 2022050615490817

After reading data: 2022050615491019

After sending ack: 2022050615491020

I have highlighted the seconds bold.

How do I reduce the time that stream.read is taking to read? I have tried to wrap the network stream in a BufferedStream as well, but it didn't help.

CodePudding user response:

At the moment, you are performing a read loop that keeps going until Read returns a non-positive number; in TCP, this means you are waiting until the other end hangs up (or at least hangs up their outbound socket) until you get out of that loop. I suspect what is happening is that the other end is giving up on you, closing their connection, and only then do you get out of the loop.

Basically: you can't loop like that; instead, what you need to do is to carefully read until either EOF (bytes <= 0) or until you have at least one complete frame that you can respond to, and in the latter case: respond then. This usually means a loop more like (pseudo-code):

while (TryReadSomeMoreData()) // performs a read into the buffer, positive result
{
    // note: may have more than one frame per successful 'read'
    while (TryParseOneFrame(out frame)) 
    {
        ProcessFrame(frame); // includes sending responses
        // (and discard anything that you've now processed from the back-buffer)
    }
}

(parsing a frame here means: following whatever rules apply about isolating a single message from the stream - this may mean looking for a sentinel value such as CR/LF/NUL, or may mean checking if you have enough bytes to read a header that includes a length, and then checking that you have however-many bytes the header indicates as the payload)

This is a little awkward if you're using MemoryStream as the backlog, as the discard step is not convenient; the "pipelines" API is more specifically designed for this, but: either way can work.

Secondly: you may prefer async IO, although sync IO is probably fine for a simple client application with only one connection (but not for servers, which may have many many connections).

  • Related