1

Possible Duplicate:
TcpClient send data and receive data over network
Loop until TcpClient response fully read

I am trying to send a file from a server to a client over TCP.

Server-side code, sending file:

NetworkStream netStream = client.GetStream();
FileStream fs = new FileStream("usb.exe",FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data,0, data.Length);
fs.Flush();
fs.Close();

netStream.Write(data, 0, data.Length);
netStream.Flush();

Client-side code, receive file:

FileStream str = new FileStream("usb.exe", FileMode.Create, FileAccess.Write);
byte[] data = new byte[1024];

while ((dataCitit = netStream.Read(data,0, data.Length)) > 0)
    {
         Thread.Sleep(25);
         Application.DoEvents();

         str.Write(data, 0, dataCitit);
         totalbytes += dataCitit;                      
    }
str.Close();

Can someone point where I am getting it wrong ?

The file has 1036 kb, and it sends only 1032 kb and then gets stuck it won't get out the while loop on the client-side.

Also if I close the server and open it really quick it sends the last bytes and the files sends completely. (this file opens perfectly)

I think it`s a problem on the server side not sending all the bytes but why and where...

Community
  • 1
  • 1
Spreadzz
  • 289
  • 3
  • 6
  • 13

1 Answers1

6

Well this is a problem in your server-side code to start with:

fs.Read(data,0, data.Length);

You're ignoring the value returned by Read. Never do that. With FileStream you're possibly okay, but I personally wouldn't trust it anyway. If you're using .NET 4, you don't need to do this anyway - just use Stream.CopyTo.

On the client-side code, your biggest initial problem is that you're doing all of this on the UI thread. That's a terrible idea - the UI will freeze if there's a network glitch, as the Read call is blocking.

Again, just use Stream.CopyTo, but do it in a background thread.

Additionally, in all of these cases, use a using statement for the streams, so that you close them cleanly whatever happens.

That's all just general hygiene. Now, as for why you're hanging...

... you're not closing the network stream on the server side. Therefore you never reach the end of the stream on the client side. If you only need to use the connection for a single file, then the answer is simple: just close the connection on the server side.

If, however, you need to use the same connection for multiple files, then you need more protocol - you need to some way of indicating the end of the data. There are three common ways of doing that:

  • Write the length of the data before the data itself, then on the reading side, first read the length, then read that many bytes, failing if the stream finishes before you've done so. This requires that you know how much data you're going to write before you start writing.
  • Use an "end of data" marker which you can detect on the reading side; this is a pain in general, as it requires escaping the marker if it appears in the text itself.
  • A variation on the first approach, where you write a length-prefixed chunk at a time, then a zero-length chunk to indicate "end of data". This is pretty flexible, but obviously a bit more work than the first approach if the first approach actually works for you.
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you for the answer, i was just coming to edit my question. It's like you said, it is because i do not close the NetworkStream in my server side. I will fallow your advice and use on of the above approaches because i do not want to close the stream. Once again thank you. – Spreadzz Nov 23 '12 at 07:47
  • Also if you can show me an example of the first approach writing the legth of the data, if will be very usefull. – Spreadzz Nov 23 '12 at 07:52
  • @Spreadzz: No, you should try it yourself and then ask a specific question if you have problems. You might want to consider using `BinaryWriter` and `BinaryReader` which make things simpler. – Jon Skeet Nov 23 '12 at 08:06
  • Correct me if i am wrong the BinaryReader and BinaryWriter is for writing and reading and end of data marker ? – Spreadzz Nov 25 '12 at 04:32
  • One more question, on the client side my int dataCitit = netStream.Read(data,0, data.Length) will there ever be 0 if i do not close the stream on the server side ? – Spreadzz Nov 25 '12 at 07:33
  • @Spreadzz: No, you can use BinaryReader and BinaryWriter for everything. And yes, if you don't close the stream, Read will never return 0. – Jon Skeet Nov 25 '12 at 08:35
  • I used the first method writing the length before and sending it. But i also managed to get it working with using, while (netStream.DataAvailable) loop read and write ,and brake if not, is this not a good alternative ? why ? Thank you for the answers Jon, been very helpfull – Spreadzz Nov 25 '12 at 18:25
  • @Spreadzz: No, `DataAvailable` is definitely *not* a good alternative. It would mean that if you had a network glitch, your code would *think* it had read everything, when actually there was more data coming. – Jon Skeet Nov 25 '12 at 18:37
  • true. Also i am now having a diffrent problem. When i send a 700mb file, my servers private memory grows to 700,000 K and my computers performance is crippled badly and then if i try to send another 700mb file, it throws me an System.OutOfMemoryException. can you tell me what am i doing wrong ? or not doing... – Spreadzz Nov 25 '12 at 18:45
  • @Spreadzz: You're now asking something different to your original question. Please ask it in a *new* question, rather than trying to add new questions in comments. – Jon Skeet Nov 25 '12 at 18:46