17

I am trying to read all data present in the buffer of the Machine connected through TCP/IP but i don't know why i am not getting all data ,some data is getting Missed. Here is the code that i am using ..

using (NetworkStream stream = client.GetStream())
{
    byte[] data = new byte[1024];
    int numBytesRead = stream.Read(data, 0, data.Length);
    if (numBytesRead > 0)
    {
       string str= Encoding.ASCII.GetString(data, 0, numBytesRead);
    }
}

Please tell me what i am missing to get all the data from the machine. Thanks in advance..

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
shubham Hegdey
  • 507
  • 5
  • 8
  • 15
  • 1
    any chance this can have anything to do with the fact that you're explicitly reading at most 1024 bytes? – decPL Sep 26 '14 at 11:35
  • @decPL Ok So how can i read all the data? – shubham Hegdey Sep 26 '14 at 11:36
  • 1
    What is exactly missing? Begin of the stream, end, or random bytes? Are you able recognize end of the stream from the byte sequence? Do you know expected length of the data? – Aik Sep 26 '14 at 11:40
  • @Aik It is missing random bytes.And data length is not known it can be anything? – shubham Hegdey Sep 26 '14 at 11:44
  • 1
    No, it cannot be anything. You need to define a protocol if you don't want to wait until the client closes the connection. Otherwise - keep reading until the client closes the connection. – CodeCaster Sep 26 '14 at 11:44
  • @CodeCaster My machine has the feature to store the data into the buffer if there is no client listening/connected to the machine.So my requirement is if i connects to the machine in that case whatever/all data is there in the buffer of the machine,my code should be able to read it... – shubham Hegdey Sep 26 '14 at 11:49
  • I'm not sure what you're saying there or how that is relevant to what I said in my comment. – CodeCaster Sep 26 '14 at 11:50
  • @CodeCaster I just wanted to ask how i can use my posted code to get all the data from the buffer of the machine – shubham Hegdey Sep 26 '14 at 11:53
  • And I'm not sure whether you know what that means and that actually is what you want. If by "the buffer of the machine" you mean "the data received until now", which may or may not be all data the other party sent you, then yes, you can use `NetworkStream.DataAvailable`. – CodeCaster Sep 26 '14 at 11:56
  • @shubham Hegdey are you sure data are missing? The problem can be in Encoding.ASCII.GetString as well. Are you transferring text? Is the text encoded as ASCII (only 128 characters)? – Aik Sep 26 '14 at 12:06
  • @Aik Yes it is .Please check the last answer given by `GeorgeChond`.Is his code more meaningfull in comparison to mine – shubham Hegdey Sep 26 '14 at 12:09
  • @shubham Hegdey GeorgeChond answer doesn't answer me my questions: Is the text encoded as ASCII (only 128 characters)? The conversion from bytes to string can be the problematic part. – Aik Sep 26 '14 at 12:12

8 Answers8

28

The problem with your code is that you will not get all the data if the data size is bigger than the buffer size (1024 bytes in your case) so you have to Read the stream inside the loop. Then you can Write all the data inside a MemoryStream until the end of the NetworkStream.


      string str;
      using (NetworkStream stream = client.GetStream())
      {
            byte[] data = new byte[1024];
            using (MemoryStream ms = new MemoryStream())
            {

                int numBytesRead ;
                while ((numBytesRead = stream.Read(data, 0, data.Length)) > 0)
                {
                    ms.Write(data, 0, numBytesRead);


                }
               str = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
            }
        }
George Chondrompilas
  • 3,167
  • 27
  • 35
  • 1
    No, in str you will get the whole string which is stored in the `NetworkStream` the time you read it. – George Chondrompilas Sep 26 '14 at 12:07
  • You mean to say that all the data available in the buffer .Am i right? – shubham Hegdey Sep 26 '14 at 12:10
  • Also a possible solution with using MemoryStream inside NetworkStream :) +1 If you want an approach that uses your code and extends it check the other answer aswell. Try to debug the code you use and understand what is happening at each step, this might help you. – Paul Weiland Sep 26 '14 at 12:16
  • I am getting error at ` while (numBytesRead = stream.Read(data, 0, data.Length) > 0)` can not convert bool to int and `buffer` does not exists in the current context and at the last line of the code `Encoding.ASCII.GetString(ms.ToArray(), 0, ms.Length);` – shubham Hegdey Sep 26 '14 at 12:35
  • Well, I forgot to add parenthesis in the while that's why you getting that error (I edited my answer) and I am not using the buffer in the Encoding part. There is no `buffer` in the code at all. – George Chondrompilas Sep 26 '14 at 12:39
  • Again i am getting error at ` ms.Write(buffer, 0, numBytesRead); ` the name `buffer` does not exists in the current context – shubham Hegdey Sep 26 '14 at 12:44
  • Oops, sorry about that it's `ms.Write(data, 0, numBytesRead);` – George Chondrompilas Sep 26 '14 at 12:45
  • Ok Thnaks .but now also getting error at `Encoding.ASCII.GetString(ms.ToArray(), 0, ms.Length);` The best overloaded method has some invalid arguments..Please check – shubham Hegdey Sep 26 '14 at 12:47
  • Try `Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length)` – George Chondrompilas Sep 26 '14 at 12:49
  • I have one query as what does it means `byte[] data = new byte[1024];` `1024` in the above code.Does it mean the present in one line? – shubham Hegdey Sep 26 '14 at 13:01
  • Sorry, I didn't get that. – George Chondrompilas Sep 26 '14 at 13:05
  • Does `byte[] data = new byte[1024];` means the byte data for one line of text to get from the machine because everytime i am seeing that it is returning line by line data – shubham Hegdey Sep 26 '14 at 13:08
  • Nothing to do with the lines of text. I means that in that array 1024 bytes of data are temporarily stored in order to be saved in the `MemoryStream`. For example in this array a lot of lines of text can be stored. – George Chondrompilas Sep 26 '14 at 13:14
  • Can't we just use `networkStream.CopyTo(memoryStream);`? (`stream.CopyTo(ms);`) – Wickramaranga Oct 31 '16 at 17:43
  • 7
    Be careful. This solution CLOSE connection after `using` section ends. – FoKycHuK Dec 24 '16 at 15:32
  • For anyone else reading this for string data why not just use the following: `StreamReader reader = new StreamReader(stream); string data = reader.ReadToEnd();` – csmith Feb 25 '18 at 03:25
  • Any idea why I get the next error? `System.IO.IOException: Unable to read data from the transport connection: Operation on non-blocking socket would block.` – Daniel Reyhanian May 28 '19 at 08:34
  • @DanielReyhanian does that help? https://stackoverflow.com/questions/46307089/cannot-read-from-stream-ioexception-non-blocking-socket-would-block-using-bou – George Chondrompilas May 28 '19 at 09:27
  • @GeorgeChond It was a problem with my server side. Cheers. – Daniel Reyhanian May 31 '19 at 00:00
11

This example from MSDN: NetworkStream.DataAvailable shows how you can use that property to do so:

// Examples for CanRead, Read, and DataAvailable. 
// Check to see if this NetworkStream is readable. 
if(myNetworkStream.CanRead)
{
    byte[] myReadBuffer = new byte[1024];
    StringBuilder myCompleteMessage = new StringBuilder();
    int numberOfBytesRead = 0;

    // Incoming message may be larger than the buffer size. 
    do{
         numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, myReadBuffer.Length);

         myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

    }
    while(myNetworkStream.DataAvailable);

    // Print out the received message to the console.
    Console.WriteLine("You received the following message : " +
                                 myCompleteMessage);
}
else
{
     Console.WriteLine("Sorry.  You cannot read from this NetworkStream.");
}
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
dariogriffo
  • 4,148
  • 3
  • 17
  • 34
  • And what does this example do? Is `NetworkStream.DataAvailable` reliable for OP's purpose? When does it become `false`? – CodeCaster Sep 26 '14 at 11:48
  • I becomes false when no more data is in the socket, and why would not be reliable? – dariogriffo Sep 26 '14 at 11:51
  • 1
    No. `NetworkStream.DataAvailable` being `false` just indicates there's no data in the receiver's receive buffer. It doesn't mean that the sender is done sending, so it can't be used to implement a protocol and it won't solve OP's problem. – CodeCaster Sep 26 '14 at 11:54
  • 2
    Read yourself, you are saying I'm right, and he asked to read all the data in the stream. You are going one step beyond and I agree with you, he needs to implement a protocol, but that is not the question here, he ask how to read all the data in the stream. – dariogriffo Sep 26 '14 at 11:56
  • 1
    I highly doubt that is what OP wants, but you're right. – CodeCaster Sep 26 '14 at 12:01
  • Me too, he will make a new question, and better to crack himself trying to understand, we all went through that once :D – dariogriffo Sep 26 '14 at 12:02
2

Try this code:

using (NetworkStream stream = client.GetStream())
    {
         while (!stream.DataAvailable)
         {
             Thread.Sleep(20);
         }
        
         if (stream.DataAvailable && stream.CanRead)
         {
              Byte[] data = new Byte[1024];
              List<byte> allData = new List<byte>();
        
              do
              {
                    int numBytesRead = stream.Read(data,0,data.Length);
    
                    if (numBytesRead == data.Length)
                    {
                         allData.AddRange(data);
                    }
                    else if (numBytesRead > 0)
                    {
                         allData.AddRange(data.Take(numBytesRead));
                    }                                    
               } while (stream.DataAvailable);
          }
    }
      

Hope this helps, it should prevent that you miss any data sended to you.

Robin Kanters
  • 5,018
  • 2
  • 20
  • 36
Paul Weiland
  • 727
  • 10
  • 24
2

Try this:

 private string GetResponse(NetworkStream stream)
    {
        byte[] data = new byte[1024];
        using (MemoryStream memoryStream = new MemoryStream())
        {
            do
            {
                stream.Read(data, 0, data.Length);
                memoryStream.Write(data, 0, data.Length);
            } while (stream.DataAvailable);

            return Encoding.ASCII.GetString(memoryStream.ToArray(), 0, (int)memoryStream.Length);
        }
    }
Popa Andrei
  • 2,299
  • 21
  • 25
  • 1
    I would replace line 8 & 9 by `var readCount = stream.Read(data, 0, data.Length);` and `memoryStream.Write(data, 0, readCount);` respectively. This way one doesn't get trailing 0 bytes which translate into `"\0"` null chars in the output string. – Petru Zaharia May 28 '20 at 20:45
1

The synchronous method sometimes does not display the request body. Using the asynchronous method stably displays request body.

string request = default(string);
StringBuilder sb = new StringBuilder();

byte[] buffer = new  byte[client.ReceiveBufferSize];
int bytesCount;

if (client.GetStream().CanRead)
{
    do
    {
        bytesCount = client.GetStream().ReadAsync(buffer, 0, buffer.Length).Result;
        sb.Append(Encoding.UTF8.GetString(buffer, 0, bytesCount));
    }
    while(client.GetStream().DataAvailable);

    request = sb.ToString();
}
shmnff
  • 647
  • 2
  • 15
  • 31
0

TCP itself does not have any ways to define "end of data" condition. This is responsibility of application level portocol.

For instance see HTTP request description:

A client request (consisting in this case of the request line and only one header field) is followed by a blank line, so that the request ends with a double newline

So, for request end of data is determined by two newline sequences. And for response:

Content-Type specifies the Internet media type of the data conveyed by the HTTP message, while Content-Length indicates its length in bytes.

The response content size is specified in header before data. So, it's up to you how to encode amount of data transferred at once - it can be just first 2 or 4 bytes in the beginning of the data holding total size to read or more complex ways if needed.

dewaffled
  • 2,850
  • 2
  • 17
  • 30
0

for my scenario, the message itself was telling the length of subsequent message. here is the code

 int lengthOfMessage=1024;
 string message = "";
 using (MemoryStream ms = new MemoryStream())
 {
      int numBytesRead;
      while ((numBytesRead = memStream.Read(MessageBytes, 0, lengthOfMessage)) > 0)
      {
            lengthOfMessage = lengthOfMessage - numBytesRead;
            ms.Write(MessageBytes, 0, numBytesRead);
      }
      message = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
 }
Asad Durrani
  • 2,197
  • 1
  • 15
  • 12
0

@George Chondrompilas answer is correct but instead of writing it by yourself you can use CopyTo function which does the same :

https://stackoverflow.com/a/65188160/4120180

Stav Bodik
  • 2,018
  • 3
  • 18
  • 25