如何修复Win套接字中损坏的byte []-s [英] How to fix corrupt byte[]-s in win socket

查看:58
本文介绍了如何修复Win套接字中损坏的byte []-s的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

服务器端我有以下代码:

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文件时,其内容不正确。任何类型的文件到二进制转换是否都有其他选择?
谢谢。

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.

推荐答案

您制定的框架协议似乎像这样工作:

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

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

其中 L 代表32位整数(使用哪个字节序?)指示 D ata的长度。

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

为什么要减去3?你不应该这会导致最后3个字节被砍掉。

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

然后,当填充消息缓冲区时,您将开始写字节3,即最后一个字节 L

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

这将导致读者解释错误的数据长度。您应该从字节4开始。

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

然后采用这种方法:

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.

这篇关于如何修复Win套接字中损坏的byte []-s的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆