How to receive large file over networkstream c#? - c#

Im connecting 2 devices over TCPClient and TCPListener and im sending just a string for now and its all working:
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Server!");
clientStream.Write(buffer, 0 , buffer.Length);
clientStream.Flush();
and then
bytesRead = clientStream.Read(message, 0, 4096);
ASCIIEncoding encoder = new ASCIIEncoding();
Console.WriteLine("Mensageee"+ encoder.GetString(message, 0, bytesRead));
But now i need to send a large file over it like 10mb or maybe more so should i use this?
string doc = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
byte[] file = File.ReadAllBytes(doc + filedir)
byte[] fileBuffer = new byte[file.Length];
TcpClient clientSocket = new TcpClient(ip, port);
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Write(file.ToArray(), 0, fileBuffer.GetLength(0));
networkStream.Close();
And how should i receive all this file and then save it somewhere?
Any help is welcome thanks o/

The short answer is, you send a byte[] multiple times...
Essentially, you will need to fill a buffer ('byte[]') with a subset of the file:
int count = fileIO.Read(buffer, 0, buffer.Length);
And then send the buffer over the socket:
clientSocket.Send(buffer, 0, count);
Just do these two processes until you have sent the entire file... (Which will be when count <= 0) However, the server has to know how many bytes to read... so we should start out by sending a Int64 with the file's length.
What we have so far...
using (var fileIO = File.OpenRead(#"C:\temp\fake.bin"))
using(var clientSocket = new System.Net.Sockets.TcpClient(ip, port).GetStream())
{
// Send Length (Int64)
clientSocket.Write(BitConverter.GetBytes(fileIO.Length, 0, 8));
var buffer = new byte[1024 * 8];
int count;
while ((count = fileIO.Read(buffer, 0, buffer.Length)) > 0)
clientSocket.Write(buffer, 0, count);
}
Server Side
Int64 bytesReceived = 0;
int count;
var buffer = new byte[1024*8];
// Read length - Int64
clientStream.Read(buffer, 0, 8);
Int64 numberOfBytes = BitConverter.ToInt64(buffer, 0);
using(var fileIO = File.Create("#c:\some\path"))
while(bytesReceived < numberOfBytes && (count = clientStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileIO.Write(buffer, 0, count);
bytesReceived += count;
}

Related

how to read data from a FileStream and add them to a queue in midwhile

i have a client as below
TcpClient client = new TcpClient("127.0.0.1", 13000);
var stream = client.GetStream();
byte[] buff = new byte[1024];
List<byte> bytequeue = new List<byte>();
MemoryStream ms = new MemoryStream();
int count = 0;
do
{
count = stream.Read(buff, 0, 1024);
ms.Write(buff, 0, count);
} while (stream.CanRead && count > 0);
stream.Flush();
client.Close();
and i would like to add the byte just read inside the while loop to a queue (list of byte)
Using linq you probably can do this:
bytequeue = bytequeue.Concat(buff.ToList());
Both ToList and Concat are Linq functions, they actually do what their names say.
I did not write a complete test application. See also
https://www.techiedelight.com/convert-array-to-list-csharp/

TCP socket isn't reading

private byte[] ResponseAsync(byte[] buffer, string ip, int port)
{
byte[] buffer_ = new byte[10000]; // receiving buffer 10KB
TcpClient client = new TcpClient(ip, port);
NetworkStream stream = client.GetStream();
stream.Write(buffer, 0, buffer.Length);
//await write;
int i = 0;
while (stream.DataAvailable)
{
MessageBox.Show(i.ToString());
i = stream.Read(buffer_, 0, 1024);
}
return buffer_.Take(i).ToArray();
}
the code was async but I thought I was doing somethign wrong so made it synchrone
You're overwriting the beginning of your buffer each time you do a read and will only return the data read in the last iteration of the while loop.
As such you'll need to increment i with the amount of data read and then use that as the offset when copying data in to your buffer.
private byte[] ResponseAsync(byte[] buffer, string ip, int port)
{
byte[] buffer_ = new byte[10000]; // receiving buffer 10KB
TcpClient client = new TcpClient(ip, port);
NetworkStream stream = client.GetStream();
stream.Write(buffer, 0, buffer.Length);
//await write;
int i = 0;
while (stream.DataAvailable)
{
MessageBox.Show(i.ToString());
// write data to the appropriate point in buffer_ and update i
i += stream.Read(buffer_, i, 1024);
}
return buffer_.Take(i).ToArray();
}
Be aware though that if you receive more than 10,000 bytes this will throw an exception.
The chances are that you'll not read all the data from the stream as stream.DataAvailable will only say whether there's data available to be read not that the stream has finished.

How to get all data from NetworkStream

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

TcpClient reading data and populating array

Currently in the process of writing some TCP socket code and running into a small issue.
Basically where I am confused is the following couple of lines of code.
NetworkStream clientStream = tcpClient.GetStream();
List<Byte> fullMessage = new List<Byte>();
Byte[] message = new Byte[4096];
Byte[] currentMessage = new Byte[4096];
Int32 bytesRead = 0;
if (clientStream.CanRead)
{
do
{
bytesRead = clientStream.Read(message, 0, 4096);
Array.Resize<Byte>(ref currentMessage, bytesRead);
Array.Copy(message, currentMessage, bytesRead);
fullMessage.AddRange(currentMessage);
} while (clientStream.DataAvailable);
}
Specifically regarding the best way to handle the fact even though the message byte array is declared at 4096 bytes the amount of data retrieved is arbitrary and cannot be computed.
So is the way I am handling the response considered a reasonable solution or is there a better way? (IE: Creating a new sized array based on the bytesRead value)
Use a memory stream:
NetworkStream clientStream = tcpClient.GetStream();
MemoryStream messageStream = new MemoryStream();
byte[] inbuffer = new byte[65535];
if (clientStream.CanRead)
{
do
{
var bytesRead = clientStream.Read(inbuffer, 0, buffer.Length);
messageStream.Write(inbuffer, 0, bytesRead);
} while (clientStream.DataAvailable);
}
messageStream.Position = 0;
var completeMessage = new byte[messageStream.Length];
messageStream.Write(completeMessage, 0, messageStream.Length);
If you know that the message won't exceed 4096 bytes, then you can write something like this:
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = clientStream.Read(message, totalBytesRead, message.Length - totalBytesRead)) !=0)
{
totalBytesRead += bytesRead;
}
totalBytesRead is used to tell clientStream.Read where to put the data that it copies.
clientStream.Read returns 0 if there is no data available.
Note that with this setup, you can't read more than message.Length bytes. If your packets can be larger, then I suggest making your buffer bigger. I wouldn't recommend continually resizing the array because that will end up fragmenting the large object heap (if messages become larger than 80 KB), and at some point you have to set a maximum on the size a message can be--even if you handle "arbitrarily large" messages.

Convert Byte [] to PDF

With help of this question C# 4.0: Convert pdf to byte[] and vice versa i was able to convert byte[] to PDF. Byte array length is 25990 approx. When i try to open the PDF it says file is corrupted. What could be the reason?
I tried the BinaryWriter but it creates PDF of 0 KB.
It's a response from a Web Service
Sample Code
WebResponse resp = request.GetResponse();
var buffer = new byte[4096];
Stream responseStream = resp.GetResponseStream();
{
int count;
do
{
count = responseStream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, responseStream.Read(buffer, 0, buffer.Length));
} while (count != 0);
}
resp.Close();
byte[] memoryBuffer = memoryStream.ToArray();
System.IO.File.WriteAllBytes(#"E:\sample1.pdf", memoryBuffer);
int s = memoryBuffer.Length;
BinaryWriter binaryWriter = new BinaryWriter(File.Open(#"E:\sample2.pdf", FileMode.Create));
binaryWriter.Write(memoryBuffer);
You are reading twice from the stream but only writing one buffer. Change this:
count = responseStream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, responseStream.Read(buffer, 0, buffer.Length));
To this:
count = responseStream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, count);
It seems your missing some bytes there because you have one unnecessary read. Try this:
do
{
count = responseStream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, count);
} while (count != 0);

Categories

Resources