How to fix corrupt byte[]-s in win socket

不羁的心 提交于 2019-12-14 03:21:34

问题


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.


回答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.



来源:https://stackoverflow.com/questions/37206139/how-to-fix-corrupt-byte-s-in-win-socket

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!