Отправка больших сериализованных объектов через сокеты терпит неудачу только при попытке увеличить массив байтов, но нормально при использовании массивного массива байтов.

У меня есть код, в котором я пытаюсь увеличить массив байтов, получая данные через сокет. Это ошибка.

    public bool ReceiveObject2(ref Object objRec, ref string sErrMsg)
    {
        try
        {
            byte[] buffer = new byte[1024];
            byte[] byArrAll = new byte[0];
            bool bAllBytesRead = false;

            int iRecLoop = 0;

            // grow the byte array to match the size of the object, so we can put whatever we 
            // like through the socket as long as the object serialises and is binary formatted 
            while (!bAllBytesRead)
            {
                if (m_socClient.Receive(buffer) > 0)
                {
                    byArrAll = Combine(byArrAll, buffer);
                    iRecLoop++;
                }
                else
                {
                    m_socClient.Close();
                    bAllBytesRead = true;
                }
            }

            MemoryStream ms = new MemoryStream(buffer);
            BinaryFormatter bf1 = new BinaryFormatter();
            ms.Position = 0;
            Object obj = bf1.Deserialize(ms);
            objRec = obj;

            return true;
        }
        catch (System.Runtime.Serialization.SerializationException se)
        {
            objRec = null;
            sErrMsg += "SocketClient.ReceiveObject " + "Source " + se.Source + "Error : " + se.Message;
            return false;
        }
        catch (Exception e)
        {
            objRec = null;
            sErrMsg += "SocketClient.ReceiveObject " + "Source " + e.Source + "Error : " + e.Message;
            return false;
        }
    }

    private byte[] Combine(byte[] first, byte[] second)
    {
        byte[] ret = new byte[first.Length + second.Length];
        Buffer.BlockCopy(first, 0, ret, 0, first.Length);
        Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
        return ret;
    }    

Ошибка: mscorlibError: входной поток не является допустимым двоичным форматом. Начальное содержимое (в байтах): 68-61-73-43-68-61-6E-67-65-73-3D-22-69-6E-73-65-72...

Тем не менее, когда я просто обманываю и использую МАССИВНЫЙ размер буфера, все в порядке.

        public bool ReceiveObject(ref Object objRec, ref string sErrMsg)
    {
        try
        {
            byte[] buffer = new byte[5000000];

            m_socClient.Receive(buffer);
            MemoryStream ms = new MemoryStream(buffer);
            BinaryFormatter bf1 = new BinaryFormatter();

            ms.Position = 0;
            Object obj = bf1.Deserialize(ms);
            objRec = obj;

            return true;
        }
        catch (Exception e)
        {
            objRec = null;
            sErrMsg += "SocketClient.ReceiveObject " + "Source " + e.Source + "Error : " + e.Message;
            return false;
        }
    }

Это действительно убивает меня. Я не знаю, почему он не работает. Я также поднял Комбайн из предложения здесь, так что я почти уверен, что это не неправильно?

Я надеюсь, что кто-то может указать, где я ошибаюсь


person FinancialRadDeveloper    schedule 25.01.2010    source источник


Ответы (2)


Этот метод Combine является очень дорогим способом увеличения массива, особенно когда MemoryStream разработан для решения этой проблемы; и другие ответы верны: вы должны проверить количество прочитанных байтов:

using(MemoryStream ms = new MemoryStream()) {
    int bytesRead;
    while((bytesRead = m_socClient.Receive(buffer)) > 0) {
        ms.Write(buffer, 0, bytesRead);
    }
    // access ms.ToArray() or ms.GetBuffer() as desired, or
    // set Position to 0 and read
}

Конечно, вы можете просто читать напрямую из потока (передать его своему читателю)

Кроме того, если ваша сериализация слишком велика, вы можете рассмотреть альтернативные кодировщики, такие как protobuf-net (хотя это немного изменит код). Это может решить проблему с огромным объектом.

person Marc Gravell    schedule 25.01.2010
comment
Гарх! Я думал, что это будет ответ. К сожалению, теперь он читается в цикле и зависает, когда больше не осталось байтов. Я не знаю, почему это происходит, потому что я думал, что он просто вернет ноль, а затем выйдет. - person FinancialRadDeveloper; 26.01.2010
comment
Я думаю, что мне нужно будет проверить прочитанные байты, и если это меньше, чем буфер, который выходит из цикла, поскольку дойдя до конца, он зависает. Я предполагаю, что он ждет, пока произойдет еще одна отправка, поскольку он завершил первое получение, и если бы вы позвонили другому, вы бы ожидали еще одну загрузку данных. - person FinancialRadDeveloper; 26.01.2010
comment
@AlanR - в этом случае убедитесь, что удаленный поток закрыт. Если намерение состоит в том, чтобы оставить его открытым, то да: вам нужно будет отслеживать свой собственный прогресс с помощью установленного объема данных. - person Marc Gravell; 26.01.2010
comment
Я идиот, я закомментировал Close(); поздно вечером, и вот почему он завис. Теперь это работает хорошо. Мне очень не понравилась отправка подхода datasize. Спасибо. Если бы у меня был ЛЮБОЙ представитель, я бы попытался дать вам немного за вашу помощь; P - person FinancialRadDeveloper; 26.01.2010

Я не совсем знаком с сетью C #, но разве вы не добавляете полные 1024 байта в буфер каждый раз, когда вы вызываете Combine() и игнорируете количество байтов, считанных из сокета? Вероятно, вам нужен хотя бы один дополнительный параметр для этой функции, указывающий, сколько байт копировать из second.

person Nikolai Fetissov    schedule 25.01.2010
comment
Буфер @Nikolai имеет фиксированный размер 1024 байта, и я должен добавить его в byArrAll. Таким образом, массивный буфер obv занимает место в конце его впустую, как и объединенный массив. Только то, что объединенный массив должен быть не более 1023 слишком большим, если вы понимаете, о чем я? - person FinancialRadDeveloper; 25.01.2010
comment
Вы должны добавить количество байтов, прочитанных из сокета, которое здесь меньше или равно 1024. - person Nikolai Fetissov; 25.01.2010