0

I have two win socket apps, server and client. The server app is at my virtual and client at host machine and the communication is OK. I am sending a ISO file (700MB) through that socket and I came across the error that received bytes are corrupt. When my file come to virtual machine, it has the original size, but the content is not OK. At the client side, I am using this code:

public class ProgramClient
    {
        public static void StartClient()
        {
            // Data buffer for incoming data.
            byte[] msg;
            try
                {
                    IPAddress ipAd = IPAddress.Parse("192.168.137.71");
                    IPEndPoint remoteEP = new IPEndPoint(ipAd, 1234);
                    Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    sender.Connect(remoteEP);

                    Console.WriteLine("Client connected to {0}", sender.RemoteEndPoint.ToString());
                    Console.WriteLine("Sending file...");
                    msg = GetBinaryFile(@"C:\TCPIP\test_big.iso");

                    byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);
                    int msgLength = BitConverter.ToInt32(msgLengthBytes, 0);
                    Console.WriteLine("int: {0}", msgLength);
                    Console.WriteLine("msgL size: {0}", msgLengthBytes.Length);

                    //join arrays, file size info, TCP header
                    byte[] result = new byte[msgLengthBytes.Length + msgLength];
                    Buffer.BlockCopy(msgLengthBytes, 0, result, 0, msgLengthBytes.Length);
                    Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);

                    //file extension info, TCP Header
                    byte extension = 2; //file extension code
                    byte[] newArray = new byte[result.Length + 1];
                    result.CopyTo(newArray, 1);
                    newArray[0] = extension;
                    result = newArray;

                    int bytesSent = sender.Send(result);
                    Console.WriteLine("result size: {0}", result.Length);

                    sender.Shutdown(SocketShutdown.Both);
                    sender.Close();

                    Console.WriteLine("\nPress ENTER to continue...");
                    Console.Read();

                }
                catch (ArgumentNullException ane)
                {
                    Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
                }
                catch (SocketException se)
                {
                    Console.WriteLine("SocketException : {0}", se.ToString());
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unexpected exception : {0}", e.ToString());
                }
        }

        private static byte[] GetBinaryFile(string filename)
        {
             byte[] bytes;
             using (FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
             {
                  bytes = new byte[file.Length];
                  file.Read(bytes, 0, (int)file.Length);
             }
             return bytes;
        }

        public static void Main(String[] args)
        {
            StartClient();
        }
    }

At the server side I have the following code:

class ProgramServer
    {

        public static void Main(String[] args)
        {
            try
            {
                StartListening();
            }
            catch (ArgumentNullException ane)
            {
                Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0}", se.ToString());
            }
            catch (Exception e)
            {
                Console.WriteLine("Unexpected exception : {0}", e.ToString());
            }
        }

        public static void StartListening()
        {
            byte[] bytes = new Byte[1024];

            while (true)
            {
                string outputPath = string.Empty;
                outputPath = @"C:\output\output";
                Console.WriteLine("Waiting for a connection...");
                Socket handler = SocketInstance().Accept();
                data = null;

                //for the TCP header, get file extension
                bytes = new byte[1];
                int bytesReceivedExtension = handler.Receive(bytes);
                string extension = GetExtension(bytes[0]);
                outputPath = outputPath + extension;

                //for the TCP header, get file size information
                bytes = new byte[4];
                int bytesReceived = handler.Receive(bytes);
                int Lenght = BitConverter.ToInt32(bytes, 0);
                Console.WriteLine("msg length: " + Lenght);
                int TotalReceivedBytes = 0;

                while (TotalReceivedBytes < Lenght)
                {
                    bytes = new byte[1024];
                    int bytesRec = handler.Receive(bytes);
                    TotalReceivedBytes = TotalReceivedBytes + bytesRec;
                    AppendAllBytes(outputPath, bytes);    
                }
                Console.WriteLine("Bytes received total: " + TotalReceivedBytes);
                Console.WriteLine(File.Exists(outputPath) ? "File received." : "File not received.");
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
            Console.WriteLine("\nPress ENTER to continue...");
            Console.Read();
        }

        private static Socket SocketInstance()
        {
            IPAddress ipAd = IPAddress.Parse("192.168.137.71");
            IPEndPoint localEndPoint = new IPEndPoint(ipAd, 1234);
            Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            listener.Bind(localEndPoint);
            listener.Listen(10);
            return listener;
        }

        public static void AppendAllBytes(string path, byte[] bytes)
        {
            using (var stream = new FileStream(path, FileMode.Append))
            {
                stream.Write(bytes, 0, bytes.Length);
            }
        }

        public static string GetExtension(byte extOfFile)
        {
            switch (extOfFile)
            {
                case 0:
                    return ".txt";
                case 1:
                    return ".png";
                case 2:
                    return ".iso";
                default:
                    return "";
            }
        }
    }

So, how can I be sure that my byte[] is OK? Because when I open that ISO file at the received side, its content is not OK. IS there some alternative for any type of file to binary conversion? Thanks.

Ferid Š. Sejdović
  • 998
  • 4
  • 18
  • 48
  • 1
    Why do you want to read the entire file in memory? That's not really scalable and a waste of resources. Anyway you're probably simply not doing anything with the return values of either `Send()` or `Receive()`. See also [Why does my client socket not receive what my server socket sends?](http://stackoverflow.com/questions/23713664/why-does-my-client-socket-not-receive-what-my-server-socket-sends). – CodeCaster May 13 '16 at 09:26
  • That is only for testing purpose and I know it is waste of resources. Return values of are fine. I get the file of 700MB at received side, but when I open it it is not OK for some reason. @CodeCaster – Ferid Š. Sejdović May 13 '16 at 09:34
  • 1
    I mean there's hardly any relevant code in your question. Please read [ask] and provide a [mcve]. Bytes don't go "corrupt" by being transferred, the problem must be either in your sending or your receiving side. Test with smaller files and describe _exactly_ how the bytes are corrupted. Like are there missing bytes, are there too many bytes, do bytes have different values than you expect, and so on. – CodeCaster May 13 '16 at 09:35
  • OK, I put all of my code here. @CodeCaster – Ferid Š. Sejdović May 13 '16 at 09:45

1 Answers1

1

The framing protocol you made up seems to work like this:

 0  1  2  3  4  ...  N
[L][L][L][L][D][...][D]

Where L represents an 32-bit integer (in which endianness?) indicating the lenght of the Data.

First, you're sending the wrong file length:

byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);

Why do you subtract 3? You shouldn't. This causes the last 3 bytes to be chopped off the file.

Then when filling the message buffer, you start writing at byte 3, or the last byte of L:

Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);

This will cause the reader to interpret an incorrect data length. You should start at byte 4.

Third, when writing the file, you shouldn't append the entire buffer, but only the bytes that Receive() actually wrote in the buffer:

bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
TotalReceivedBytes = TotalReceivedBytes + bytesRec;
AppendAllBytes(outputPath, bytes, bytesRec);    

Then in that method:

public static void AppendAllBytes(string path, byte[] bytes, int bufferLength)
{
    using (var stream = new FileStream(path, FileMode.Append))
    {
        stream.Write(bytes, 0, bufferLength);
    }
}

And this is why you shouldn't write your own protocol and socket code if you don't know very well what you're doing. Leverage existing protocols and libraries instead.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Hi. First of all, thanks for the answer. At first I was sending a txt file and I was getting 3 anonymous bytes (???) so that's why I subtract 3. OK, besides the joining bytes part, is everything else OK? Thanks. – Ferid Š. Sejdović May 13 '16 at 09:55
  • @Ferid yeah, there's a third problem, see edit. Your text file probably was 1021 bytes long. – CodeCaster May 13 '16 at 09:57