如何在win socket中修复损坏的byte [] - s

时间:2016-05-13 09:22:54

标签: sockets bytearray

我有两个win套接字应用,服务器和客户端。服务器应用程序位于主机上的虚拟和客户端,通信正常。我通过该套接字发送ISO文件(700MB),我遇到了接收字节已损坏的错误。当我的文件来到虚拟机时,它具有原始大小,但内容不正常。在客户端方面,我使用的是此代码:

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();
        }
    }

服务器一侧,我有以下代码:

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 "";
            }
        }
    }

那么,我如何确定我的byte []是否正常?因为当我在接收方打开该ISO文件时,其内容不正常。是否有任何类型的文件到二进制转换的替代? 感谢。

1 个答案:

答案 0 :(得分:1)

你制作的框架协议似乎是这样的:

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

其中L表示32位整数(以字节顺序表示?),表示D ata的长度。

首先,您发送的文件长度错误:

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

为什么减去3?你不应该。这会导致最后3个字节从文件中删除。

然后在填充消息缓冲区时,开始写入字节3或L的最后一个字节:

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

这将使读者解释不正确的数据长度。你应该从字节4开始。

第三,在编写文件时,不应该附加整个缓冲区,而只应附加Receive()实际写入缓冲区的字节:

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

然后用那种方法:

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

这就是为什么如果你不太了解自己在做什么,就不应该编写自己的协议和套接字代码。改为利用现有的协议和库。