thencz
thencz

Reputation: 31

C# sending files over internet

I managed to send binary data through TCP using NetworkStream and Sockets. My only problem is that when I send larger files like few hundred KB images, they don't get transferred correctly, the half of the image is missing. On the server side I Socket.Send to transfer data. On the client side I use Socket.BeginReceive with a 1024 sized buffer that's getting written into a MemoryStream, later I use new Bitmap(Stream) to convert that MemoryStream into an image that can be displayed in a PictureBox.

What method should I use to avoid data loss?

Edit: code posted

            listener = new TcpListener(myAddress, 86);
            listener.Start();
            TcpClient client = listener.AcceptTcpClient();
            ns = client.GetStream();
            byte[] buffer = new byte[1024];
            while (fileTransfer)
            {
                ms = new MemoryStream();
                do
                {
                    int length = ns.Read(buffer, 0, buffer.Length);
                    ms.Write(buffer, 0, length);
                    // with this line added the data loss apparently disappears
                    System.Threading.Thread.Sleep(1);
                } while (ns.DataAvailable);
                UpdateData();
                ms.Dispose();
                System.Threading.Thread.Sleep(10);
            }
            ns.Dispose();
            client.Close();
            listener.Stop();

Edit: the data is still corrupt sometime even with the sleep method.

Upvotes: 0

Views: 2608

Answers (3)

thencz
thencz

Reputation: 31

OK I solved it by sending the size of the data before sending the actual data. The reason it didn't work that I wrongly assumed that the transfer was immediate. That's why the Sleep() method in the receiver loop made a difference but did NOT solve the problem. I understand that I can't rely on DataAvailable in this context. Even checking the length of the received data won't work because the client might send data after the loop has finished. Checking the file size (if the data is bigger than the buffer on the receiver side) is the best solution I found so long.

Upvotes: 0

tzot
tzot

Reputation: 95951

I suggest you change this loop:

do
{
    int length = ns.Read(buffer, 0, buffer.Length);
    ms.Write(buffer, 0, length);
    // with this line added the data loss apparently disappears
    System.Threading.Thread.Sleep(1);
} while (ns.DataAvailable);

into:

do
{
    int length = ns.Read(buffer, 0, buffer.Length);
    ms.Write(buffer, 0, length);
} while (length > 0);

That is, read until the end of data (i.e ns.Read returns no data). Read blocks until there are some data or the socket is closed (or some exception is thrown). I removed the useless sleep.

Upvotes: 1

wal
wal

Reputation: 17729

Most likely (at a guess) you are not reading from the stream on the client side correctly.

You need to read the result of the EndReceive ( ) method to see how much data you actually read - it may not be the size of your buffer (1024 bytes in this case)

So:
a) When calling BeginReceive are you passing a callback?
b) If Yes, are you reading the result of this and writing the appropriate amount of bytes into your memory stream?

ie:

public void ReceiveCallback( IAsyncResult result)
{

    var buffer = (byte[])result.AsyncState;
    int bytesRead = socket.EndReceive();
    memoryStream.Write (buffer, 0, bytesRead);//bytesRead may not be 1024!
}

Upvotes: 0

Related Questions