Отправка больших сериализованных объектов через сокеты завершается неудачей только при попытке увеличить массив байтов, но нормально при использовании массивного массива байтов
-
22-09-2019 - |
Вопрос
У меня есть код, в котором я пытаюсь увеличить массив байтов при получении данных через мой сокет.Это приводит к ошибке.
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;
}
}
Это действительно убивает меня.Я не знаю, почему это не работает.Я также снял Комбайн с предложения здесь, так что я почти уверен, что это не делает что-то неправильно?
Я надеюсь, что кто-нибудь сможет указать, где я иду не так
Решение
Это 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 (хотя это немного изменит код).Это может устранить проблему с огромным объектом.
Другие советы
Я не очень знаком с сетевым интерфейсом C #, но разве вы не добавляете полные 1024 байта в буфер каждый раз, когда вызываете Combine()
и игнорирование количества байтов, считанных с сокета?Вероятно, вам нужен по крайней мере один дополнительный параметр для этой функции, указывающий, сколько байтов нужно скопировать из second
.