数组大小由long导致的算术溢出定义

时间:2014-12-12 19:11:32

标签: c# .net arrays sockets bytearray

我正在使用套接字并将pdf,docs等小文件传输到服务器。在服务器端,我正在读取套接字数据并解析出我正在发送的文件大小。

我正在使用流,因此文件大小很长。问题是我的缓冲区是1024,所以我发送的最后一个数据包很少是1024,这意味着我最终会得到一个包含741 kbs数据的数据包,其余的缓冲区都是0。

为了解决这个问题,破坏了我的最终输出,我计算了文件大小的差异,然后创建一个新的缓冲区,只复制我需要的东西,留下垃圾。它在我的电脑上工作正常,但它会在VMware上引发算术溢出,我将要运行服务器。我认为它使用的是比我更老的.Net版本,即使我的开发PC上的目标是4.5。

这是有问题的代码。我尝试过使用check和unchecked符号,一切。有什么建议吗?

Int64 resizeTo = (int)(packet.payloadSize - packet.ms.Length);  
byte[] endByte = new byte[(int)resizeTo];
Array.Copy(packet.buff, 0, endByte, 0, endByte.Length);

编辑:有问题的方法

public void ReadCallback(IAsyncResult ar)
    {
        try 
        {
            PacketInfo packet = (PacketInfo)ar.AsyncState;
            Socket handler = packet.socket;

            int bytesRead = handler.EndReceive(ar);
            string remotePoint = handler.RemoteEndPoint.ToString();             

            if (bytesRead > 0) 
            {
                string peek = Encoding.UTF8.GetString( packet.buff );

                if ( peek.Contains(hStart ) )
                {
                    // file size
                    byte[] fSize = new byte[8];
                    Array.Copy(packet.buff, 8, fSize, 0, fSize.Length);
                    packet.payloadSize = BitConverter.ToInt64(fSize, 0);

                    // File Name and User ID
                    string[] s = peek.Split('#');

                    foreach (string t in s)
                    {
                        if (t.Contains(@"\"))
                            packet.fileName = t;

                        if (t.Trim().Length == 7)
                            packet.ADID = t;                                            
                    }                           
                }
                else if ( peek.Contains(dEnd ) )
                {
                    // Trim up last bytes of info, buffers set to1024 but if the last byte wasnt that big it gets padded with 0s by the socket
                    Int64 resizeTo = (int)(packet.payloadSize - packet.ms.Length);                              
                    byte[] endByte = new byte[(int)resizeTo];
                    Array.Copy(packet.buff, 0, endByte, 0, endByte.Length);
                    packet.ms.Write(endByte, 0, endByte.Length);                

                    long payloadSize = packet.payloadSize;
                    long streamSize = packet.ms.Length;


                    // verify file size, reject if it doesn't match checksum
                    if ( payloadSize == streamSize )
                    {
                        // Handle completed file transfer
                        FileTransferCompleted(packet.ms);
                        packet.socket.Send(Encoding.UTF8.GetBytes(sAck));

                        UpdateStatus("Payload should be: " + payloadSize + " payload was: " + streamSize + " for: " + remotePoint + "\n");
                        UpdateStatus("Sending acknowledgement and closing socket to: " + remotePoint + "\n");

                        packet.socket.Close();
                        packet = null;                          
                        return;
                    }

                    packet.socket.Send(Encoding.UTF8.GetBytes(rAck));
                    packet.ms.Position = 0;
                    UpdateStatus("Payload should be: " + packet.payloadSize + " payload was: " + packet.ms.Length + " for: " + remotePoint + "\n");
                    UpdateStatus("Sending request for retransfer to: " + remotePoint + "\n");                                       
                }
                else
                {
                    packet.ms.Write(packet.buff, 0, packet.buff.Length);
                    //UpdateStatus("Receiving data from: " + remotePoint + "\n");       // only for debug                                       
                }

                handler.BeginReceive(packet.buff, 0, packet.buff.Length,
                        SocketFlags.None,
                        new AsyncCallback(ReadCallback), packet);
                //UpdateStatus("Checking for data from: " + remotePoint + "\n");                    // only for debug
            }

        } 
        catch (Exception exc)
        {
            MessageBox.Show(exc.ToString());
        }
    }           
}

public class PacketInfo
{
    public Socket socket = null;
    public const int buffSize = 1024;
    public byte[] buff = new byte[buffSize];
    public MemoryStream ms = new MemoryStream();
    public long payloadSize;
    public string fileName = null;
    public string ADID = null;
}

编辑其余的服务器代码

public class Server
{
    // socket protocol messages
    const string hStart = "<<head>>";           // header start
    const string dEnd = "<<end>>";              // data end
    const string sAck = "<<success>>";          // received
    const string rAck = "<<resend>>";           // received, didn't match checksum, resend

    int _port;
    int _maxConnections;

    // Internal event
    ManualResetEvent allDone = new ManualResetEvent(false);
    // Public update event for status updates
    public delegate void StatusUpdateHandler(object sender, StatusUpdateEvent e);
    public event StatusUpdateHandler onStatusUpdate;
    // public event for file completion status
    public delegate void FileTransferHandler(object sender, FileTransferComplete e);
    public event FileTransferHandler onFileTransferComplete;

    public int Port {
        get { return _port; }           
    }

    public int MaxConnections {
        get { return _maxConnections; }
    }

    public Server( int port, int maxConnections )
    {
        this._port = port;
        this._maxConnections = maxConnections;
    }

    void UpdateStatus(string status)
        {
        if (onStatusUpdate == null)
        {
            Debug.WriteLine("NULL");
            return;
        }                   

            StatusUpdateEvent args = new StatusUpdateEvent(status);
            onStatusUpdate(this, args);
        }

    void FileTransferCompleted( object payload )
    {
        if ( onFileTransferComplete == null )
        {
            Debug.WriteLine("Null File Transfer Completed Event");
            return;
        }

        FileTransferComplete args = new FileTransferComplete(payload);
        onFileTransferComplete(this, args);            
    }

    public void SpinUp()
    {
        IPHostEntry ipHost = Dns.GetHostEntry("");
        IPAddress ipAddr = ipHost.AddressList[0];
        IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, _port);                      

            SocketPermission permission = new SocketPermission(
            NetworkAccess.Accept,     
            TransportType.Tcp,         
            "",                        
            SocketPermission.AllPorts  
        );

        permission.Demand();

        Socket sListener = new Socket(
            ipAddr.AddressFamily,
            SocketType.Stream,
            ProtocolType.Tcp
        );

        sListener.Bind(ipEndPoint);
        sListener.Listen(_maxConnections);

        while (true) 
        {
            allDone.Reset();

            UpdateStatus("Waiting for connections on port " + _port + ":\n");
            Debug.WriteLine("Waiting for connections.");

                    sListener.BeginAccept( 
                            new AsyncCallback(AcceptCallback),
                            sListener );

            allDone.WaitOne();
                } 
    }

    public void AcceptCallback(IAsyncResult ar)
    {
        allDone.Set();

        try
        {
            Socket listener = (Socket)ar.AsyncState;
            Socket handler  = listener.EndAccept(ar);

            UpdateStatus("Connection received from: " + handler.RemoteEndPoint + "\n" );                

            handler .NoDelay = false;

            PacketInfo packet = new PacketInfo();

            packet.socket = handler;

            handler .BeginReceive(
                packet.buff,         
                0,               
                packet.buff.Length,  
                SocketFlags.None, 
                new AsyncCallback(ReadCallback),
                packet                          
            );              
        } 
        catch ( OverflowException overflow )
        {
            MessageBox.Show(overflow.ToString());
        }
        catch (Exception exc) 
        {
            MessageBox.Show(exc.ToString());
        }
    }

客户端代码

namespace Client
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
    const string hStart = "<<head>>";           // header start
    const string dEnd = "<<end>>";          // data end
    const string sAck = "<<success>>";          // received
    const string rAck = "<<resend>>";           // resend

    BindingList<string> connections = new BindingList<string>();

    public List<byte[]> buildTransfer( FileStream fs )
    {
        List<byte[]> packets = new List<byte[]>();

        using ( fs )
        {
            using ( MemoryStream ms = new MemoryStream() )
            {
                fs.CopyTo(ms);
                ms.Position = 0;
                ms.Flush();

                byte[] header = genHeader( ms.Length, fs.Name, Environment.UserName );
                packets.Add(header);

                int incomingOffset = 0;

                while(incomingOffset < ms.ToArray().Length)
                {
                    byte[] buffer = new byte[1024];

                    int length =
                        Math.Min(buffer.Length, ms.ToArray().Length - incomingOffset);

                    if ( length < buffer.Length )
                    {
                        buffer = new byte[length + dEnd.Length];

                        byte[] endblock = Encoding.UTF8.GetBytes(dEnd);
                        Buffer.BlockCopy(ms.ToArray(), incomingOffset,
                                        buffer, 0, 
                                        length);                            
                        Buffer.BlockCopy(endblock, 0, buffer, length, endblock.Length);

                        packets.Add(buffer);
                        return packets;
                    }

                    Buffer.BlockCopy(ms.ToArray(), incomingOffset,
                                    buffer, 0, 
                                    length);



                    incomingOffset += length;
                    packets.Add(buffer);

                }               
            }
        }

        byte[] footer = new byte[1024];
        footer[0] = Encoding.UTF8.GetBytes(dEnd)[0];
        packets.Add(footer);        
        return packets;

    }

    byte[] genHeader( long fileSize, string fileName, string ADID )
    {

        byte[] header = new byte[1024];
        byte[] adid = Encoding.UTF8.GetBytes(Environment.UserName);
        byte[] fName = Encoding.UTF8.GetBytes(fileName);
        byte[] start = Encoding.UTF8.GetBytes(hStart);
        byte pad = Encoding.UTF8.GetBytes("#")[0];

        int x = 0;

        foreach( byte b in start )
        {
            header[x] = b;
            x++;
        }

        foreach( byte b in  BitConverter.GetBytes(fileSize) )
        {
            header[x] = b;
            x++;
        }

        header[x] = pad;
        x++;

        foreach( byte b in fName )
        {
            header[x] = b;
            x++;
        }

        header[x] = pad;
        x++;

        foreach( byte b in adid )
        {
            header[x] = b;
            x++;
        }

        header[x] = pad;
        x++;

        return header;
    }

    public MainForm()
    {
        InitializeComponent();
        dataGridView1.DataSource = connections;

        for( int x = 0; x < 1; x++ )
        {
            Thread nt = new Thread(connect);
            nt.Start();
            Thread.Sleep(1000);
        }

        //connect();                
    }

    void connect()
    {
        byte[] bytes = new byte[1024]; 
        Socket senderSock;

        try 
        {
            // Create one SocketPermission for socket access restrictions 
            SocketPermission permission = new SocketPermission(
                                                          NetworkAccess.Connect,    // Connection permission 
                                                          TransportType.Tcp,        // Defines transport types 
                                                          "",                       // Gets the IP addresses 
                                                          SocketPermission.AllPorts // All ports 
                                                      );

            // Ensures the code to have permission to access a Socket 
            permission.Demand();

            // Resolves a host name to an IPHostEntry instance            
            IPHostEntry ipHost = Dns.GetHostEntry("");

            // Gets first IP address associated with a localhost 
            IPAddress ipAddr = ipHost.AddressList[0];

            // Creates a network endpoint 
            IPEndPoint ipEndPoint = CreateIPEndPoint("10.212.98.71:4510");
            //IPEndPoint ipEndPoint = new IPEndPoint(ipHost.AddressList[0], 4510);

            // Create one Socket object to setup Tcp connection 
            senderSock = new Socket(
                ipAddr.AddressFamily,// Specifies the addressing scheme 
                SocketType.Stream,   // The type of socket  
                ProtocolType.Tcp     // Specifies the protocols  
            );

            senderSock.NoDelay = false;   // Using the Nagle algorithm 

            // Establishes a connection to a remote host 
            senderSock.Connect(ipEndPoint);
            connections.Add(senderSock.LocalEndPoint.ToString());
            List<byte[]> toSend = new List<byte[]>();

            using( FileStream fs = new FileStream(@"C:\Users\jdy5tnh\Downloads\b3.pdf", FileMode.Open) )
            {
                toSend = buildTransfer(fs); 
            }

            while( true )
            {
                foreach( byte[] b in toSend )
                    senderSock.Send(b);

                byte[] buffer = new byte[1024];
                senderSock.Receive(buffer);

                if (Encoding.UTF8.GetString(buffer).Contains(sAck ) )
                {
                    senderSock.Close();
                    senderSock.Dispose();
                    return;
                }
                else
                {
                    MessageBox.Show(Encoding.UTF8.GetString(buffer));
                }
            }       

        } catch (Exception exc) {
            MessageBox.Show(exc.ToString());
        }
    }

    public static IPEndPoint CreateIPEndPoint(string endPoint)
    {
        string[] ep = endPoint.Split(':');
        if (ep.Length != 2)
            throw new FormatException("Invalid endpoint format");
        IPAddress ip;
        if (!IPAddress.TryParse(ep[0], out ip)) {
            throw new FormatException("Invalid ip-adress");
        }
        int port;
        if (!int.TryParse(ep[1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port)) {
            throw new FormatException("Invalid port");
        }
        return new IPEndPoint(ip, port);
    }
}


}

2 个答案:

答案 0 :(得分:1)

改变了我的方法并解决了问题,但它突出了另一个,因为本地我在同一台PC上创建客户端和服务器,所以我的应用程序工作正常。当我在网络中的另一台PC上使用它时,它会改变我的套接字传输的大小,因此我的代码停止工作。每次我将文件发送到服务器时,传输的大小都会增加。

首先运行它的功能很好,第二次运行它增加了大约700字节,第三次运行它再次增加,等等。所以我想像上面提到的我在我的方法中有一个根本问题。服务器部分几乎是从MSDN复制的,但客户端我只是把它放在一起所以它可能是问题的根源。

谢谢大家。

int result = peek.IndexOf(dEnd, StringComparison.Ordinal);
byte[] endByte = new byte[result];

答案 1 :(得分:1)

看起来您假设每次阅读时,您都会读取正好1,024个字节(或最后一个短块)。这可能不是这样的。如果您在致电bytesRead后查看EndRead值,我认为您会发现每次阅读时您收到的字节数差异很大。

这是基于我能看到的代码。你已经遗漏了很多,尤其是对BeginRead的号召,没有这个号召,我就无法告诉你他在做什么。但根据您发布的内容和您对问题的描述,上述内容似乎是主要问题。

您需要拆分代码,使其汇编数据包,然后对其进行解析。您需要继续读取并向临时缓冲区添加字节,直到您收到该数据包的所有字节为止。然后你可以解析数据包并做你需要做的事情。

我前一段时间写了一个小编。请参阅Reading data from streams,以及Part 2Part 3