TCP socket isn't reading - c#

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.

Related

How can I show the current speed of download/upload with tcp client?

I'm creating a file transfer app which works with TcpListener and TcpClient. My app works perfectly, I'm just wondering how I can show the download/upload speed while data is transferring. I also want the app to show how many MBs are downloaded or uploaded.
Server code:
IPAddress ip = IPAddress.Parse("192.168.1.2");
int port = 9999;
TcpListener server = new TcpListener(ip, port);
server.Start();
Console.WriteLine("Waiting for client...");
TcpClient tcpClient = server.AcceptTcpClient();
Console.WriteLine("Client connected!");
NetworkStream networkStream = tcpClient.GetStream();
string path = string.Empty;
string fileName = string.Empty;
Console.Write("File:");
path = Console.ReadLine();
fileName = Path.GetFileName(path);
byte[] bytes = File.ReadAllBytes(path);
BinaryWriter bwFileName = new BinaryWriter(networkStream);
bwFileName.Write(fileName);
BinaryWriter bw = new BinaryWriter(networkStream);
bw.Write(bytes.Length);
networkStream.Write(bytes, 0, bytes.Length);
Console.ReadLine();
Client code:
IPAddress ip = IPAddress.Parse("192.168.1.2");
int port = 9999;
TcpClient client = new TcpClient();
client.Connect(ip, port);
while (true)
{
NetworkStream networkStream = client.GetStream();
int byteLenght;
string fileName = string.Empty;
BinaryReader brFilename = new BinaryReader(networkStream);
fileName = brFilename.ReadString();
BinaryReader br = new BinaryReader(networkStream);
byteLenght = br.ReadInt32();
byte[] bytes = new byte[byteLenght];
networkStream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes("C:\\Users\\XANDRO\\Desktop\\client\\" + fileName,bytes);
break;
}
Console.ReadLine();
the general approach would be to split the download/upload into chunks. I.e. instead of writing the entire byte array in one go, write chunks using the offset/length parameters.
This gives an opportunity to measure the time and report the progress after each chunk. You might also consider using a file stream and write/read chunks from this as well. Since this will limit memory usage.
Edit: Example code:
public static void Copy(Stream from, Stream to, IProgress<int> progress, int bufferSize = 4096)
{
var bytesCopied = 0;
var buffer = new byte[bufferSize];
int bytesRead;
do
{
bytesRead = from.Read(buffer, 0, buffer.Length);
to.Write(buffer, 0, bytesRead);
bytesCopied += bytesRead;
progress.Report(bytesCopied);
} while (bytesRead != 0);
}

Sending a file using TCPClient and NetworkStream in C#

I've been trying to send a file from a client to a server application using the TCPClient class in C#. Before I send the actual data, I send some additional information like the exact file size and the file name, so the server application knows how much there is to read. The funny thing is everything was fine when I tested it on 127.0.0.1 - as soon as I replaced the IP address with the actual one, the server could only read about 1,5 KByte of the data that was sent. It still gets the filename and the file size, but theres no way it's retrieving the actual data.
For testing purposes, I replaced the image I was going to send with a simple string and the transmission went alright, so I suppose there is a problem with sending and receiving the data chunks, but I'm not getting any exceptions on the client side either.
Anyone got an idea? Cheers!
Edit:
Thanks so far, this is what I have got codewise. For the client:
IPAddress ipAddress = IPAddress.Parse("xx.xx.xx.xx");
int port = 3003;
int bufferSize = 1024;
TcpClient client = new TcpClient();
NetworkStream netStream;
// Connect to server
try
{
client.Connect(new IPEndPoint(ipAddress, port));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
netStream = client.GetStream();
// Read bytes from image
byte[] data = File.ReadAllBytes("C:\\Users\\Dan\\Desktop\\asdf.jpg");
// Build the package
byte[] dataLength = BitConverter.GetBytes(data.Length);
byte[] package = new byte[4 + data.Length];
dataLength.CopyTo(package, 0);
data.CopyTo(package, 4);
// Send to server
int bytesSent = 0;
int bytesLeft = package.Length;
while (bytesLeft > 0)
{
int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;
netStream.Write(package, bytesSent, nextPacketSize);
bytesSent += nextPacketSize;
bytesLeft -= nextPacketSize;
}
// Clean up
netStream.Close();
client.Close();
And the server:
TcpListener listen = new TcpListener(3003);
TcpClient client;
int bufferSize = 1024;
NetworkStream netStream;
int bytesRead = 0;
int allBytesRead = 0;
// Start listening
listen.Start();
// Accept client
client = listen.AcceptTcpClient();
netStream = client.GetStream();
// Read length of incoming data
byte[] length = new byte[4];
bytesRead = netStream.Read(length, 0, 4);
int dataLength = BitConverter.ToInt32(length,0);
// Read the data
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
while (bytesLeft > 0)
{
int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;
bytesRead = netStream.Read(data, allBytesRead, nextPacketSize);
allBytesRead += bytesRead;
bytesLeft -= bytesRead;
}
// Save image to desktop
File.WriteAllBytes("C:\\Users\\Dan\\Desktop\\tcpimage.jpg", data);
// Clean up
netStream.Close();
client.Close();
About 1.5 KiB sounds like 1500 bytes, "the largest allowed by Ethernet at the network layer". This is the maximum transmission unit (mtu) forcing your network stack to split your file into several small packets.
You need to call the NetworkStream.Read in a loop to read every packet arrived. There's example code of this at MSDN.
Combine this with the default behavior of .NET; consolidating smaller packets to reduce the amount of packets sent, and you'll also see this behavior when sending smaller packets. This can be controlled with ServicePointManager.UseNagleAlgorithm or by using smaller scoped socket options.
Ok, don't know what I'm doing here, but in case of anyone uses this as referrence.
I got rid of unnecessary copying and done a very important improvement. Your way to calc nextPacketSize is not complete, since there could be less data, than 1024 avaliable, and you'll get extra nulls in between these chunks (I had a lot of headache with that, now so happy to figure out)
I made them as function, needed for several files, so here's code:
client
this one is almost the same
public void sendData(byte[] data, NetworkStream stream)
{
int bufferSize = 1024;
byte[] dataLength = BitConverter.GetBytes(data.Length);
stream.Write(dataLength, 0, 4);
int bytesSent = 0;
int bytesLeft = data.Length;
while (bytesLeft > 0)
{
int curDataSize = Math.Min(bufferSize, bytesLeft);
stream.Write(data, bytesSent, curDataSize);
bytesSent += curDataSize;
bytesLeft -= curDataSize;
}
}
server
public byte[] getData(TcpClient client)
{
NetworkStream stream = client.GetStream();
byte[] fileSizeBytes = new byte[4];
int bytes = stream.Read(fileSizeBytes, 0, 4);
int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
int bufferSize = 1024;
int bytesRead = 0;
while (bytesLeft > 0)
{
int curDataSize = Math.Min(bufferSize, bytesLeft);
if (client.Available < curDataSize)
curDataSize = client.Available; //This saved me
bytes = stream.Read(data, bytesRead, curDataSize);
bytesRead += curDataSize;
bytesLeft -= curDataSize;
}
return data;
}
I used some of your code for a test networking project I'm working on. I tweaked a couple things to fit the requirements of my project, but one alteration I needed to make to the original code is to add a "-4" to the line that was setting the bytesLeft variable. After that the code worked. My test file is 52KB & was transmitted successfully.
// Read the data
int bytesLeft = dataLength-4;
byte[] data = new byte[dataLength];

TCPClient. How do I receive big messages?

I have the following code:
private string Connect()
{
string responseData;
try
{
TcpClient client = new TcpClient(ServerIp, Port);
client.ReceiveBufferSize = Int32.MaxValue;
Byte[] data = Encoding.GetEncoding(1251).GetBytes(ReadyQuery);
NetworkStream stream = client.GetStream();
// send data
stream.Write(data, 0, data.Length);
// buffer
data = new Byte[65536];
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = Encoding.GetEncoding(1251).GetString(data, 0, bytes);
// close all
stream.Close();
client.Close();
return responseData;
}
I have problem with a big message. The receive message size is 22K chars. I get only part of message.
How can I receive big messages?
PS. In the debugger bytes equal 4096.
You call stream.Read in a loop until you read the entire message. If you know the message size in advance it's relatively easy:
int messageSize = 22000;
int readSoFar = 0;
byte [] msg = new byte[messageSize];
while(readSoFar < messageSize)
{
var read = stream.Read(msg, readSoFar, msg.Length - readSoFar);
readSoFar += read;
if(read==0)
break; // connection was broken
}
If the message size is part of the message (say, encoded in the first 4 bytes), you should read those first and then do as I suggested.

setting NetworkStream.ReceiveTimeout not triggering exception

This is a continuation of the this question. I am new to network programming, so I am just writing small sample stuff to gain understanding, but somewhat struggling with explaining results.
It seems setting NetworkStream.ReceiveTimeout is not working correctly when client that was supposed to be sending data simply closes before sending all the expected data.
Here is the sample code:
public static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 10001);
listener.Start();
ThreadPool.QueueUserWorkItem(WriterThread);
using (TcpClient client = listener.AcceptTcpClient())
using (NetworkStream stream = client.GetStream())
{
client.ReceiveTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
stream.ReadTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
ReceiveMessage(stream, 1024);
}
listener.Stop();
Console.WriteLine("Done.");
Console.ReadKey(true);
}
private static void WriterThread(object state)
{
using (TcpClient client = new TcpClient())
{
client.Connect(new IPEndPoint(IPAddress.Loopback, 10001));
using (NetworkStream stream = client.GetStream())
{
byte[] bytes = Encoding.ASCII.GetBytes("obviously less than 1024 bytes");
stream.Write(bytes, 0, bytes.Length);
Thread.Sleep(10000); // comment out
}
}
}
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
bufferFill += stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
This version works correctly triggering exception on the stream.Read() call. However If I comment out Thread.Sleep(10000), the client closes connection, but listener fails to recognize it. Main thread gets stuck inside the while(true) loop. The stream.Read() keeps returning zero, but no exception thrown.
Is this normal? If so how am I expected to handle abnormal client disconnections?
Yes, this sounds normal. There is no receive- or read timeout because the client has disconnected. This means that no more data is available for reading and the stream will return 0 immediately just as documented.
I would modify your ReceiveMessage method to something like the following:
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
int bytesRead = stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (bytesRead == 0)
throw new Exception("No more data available.");
bufferFill += bytesRead;
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
Clearly if the stream.Read() call returns 0 before we have received all the expected bytes there must have been some form of disconnection or similar. Either way we will never get any more data from the stream.
Edit: The Stream class has no notion of a "message". The Read method blocks until more data becomes available if none is already in the buffer. It will however return 0 when no more data can be received, which in this case means the connection is closed.

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.

Categories

Resources