TCP-клиент - данные повреждены только в некоторых частях
У меня есть клиентское приложение, которое отправляет файл на сервер. Проблема в том, что в клиентской части файл читается правильно, я могу снова сохранить байтовый массив после того, как прочитал его, и он сохранился как действительный jpg. Однако на стороне сервера в некоторых местах данные повреждены. Все, что я делаю, это продолжаю добавлять в список все входящие данные, пока клиент не закроет соединение.
Я перекрыл отправленные / полученные данные клиента и сервера, и, как вы можете видеть, есть места, где данные не совпадают: http://s16.postimage.org/mtmm1hssl/corrupted_data.png
Я не понимаю, как это возможно, я использую большой буфер, и изображение довольно маленькое, поэтому, даже когда изображение принимается сервером в виде одного "фрагмента", данные по-прежнему повреждены.
Есть идеи, почему это происходит?
ОБНОВИТЬ:
Сторона клиента:
Я загружаю изображение с помощью HttpWebRequest:
List<byte> test_buffer = new List<byte>();
using (Stream MyResponseStream = hwresponse.GetResponseStream())
{
byte[] MyBuffer = new byte[4096];
int BytesRead;
while (0 < (BytesRead = MyResponseStream.Read(MyBuffer, 0, MyBuffer.Length)))
{
for (int i = 0; i < BytesRead; i++)
{
test_buffer.Add(MyBuffer[i]); // just for testing
}
TCP_R.SendBytes(MyBuffer); // send data back to server
}
}
TCP_R.Close(); // tell server that we're done sending data
TCP_R - это класс, который обрабатывает все содержимое TCP (подключение к серверу / отправка данных)
Это функция TCP_R.SendBytes:
public void SendBytes(Byte[] data)
{
try
{
if (m_clientSocket != null)
{
m_clientSocket.Send(data);
}
}
catch (SocketException se)
{
log("send_bytes err: " + se.Message);
}
}
Обратите внимание, что я использовал test_buffer, чтобы собрать все байты, чтобы проверить, все ли получено правильно. Если я использую этот код:
MemoryStream ms = new MemoryStream(test_buffer.ToArray());
Image returnImage = Image.FromStream(ms);
returnImage.Save("image.jpg");
Изображение создано успешно. Поэтому я предполагаю, что клиент отправляет данные правильно.
Сторона СЕРВЕРА:
Я собираю данные с помощью функции OnDataReceived и собираю все данные в REQUEST_RESPONSE, который List<byte>
:
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState; // cast
int iRx = 0;
iRx = socketData.m_currentSocket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); // CAN THIS BE CAUSING THE PROBLEM!?!
int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
for (int s = 0; s < charLen; s++)
{
RESPONSE_DATA.Add(socketData.dataBuffer[s]); // Collect response data
}
WaitForData(socketData.m_currentSocket, socketData.socket_id, REQUEST_INDEX_ID);
}
}
catch (ObjectDisposedException)
{
}
catch (SocketException se)
{
}
}
ОБНОВЛЕНИЕ 2: Кажется, что эти строки вызывают проблему:
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); // CAN THIS BE CAUSING THE PROBLEM!?!
int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
Как я могу получить данные в socketData.dataBuffer без использования декодера?
РЕШЕНИЕ: Несмотря на то, что я читал напрямую из dataBuffer, строка 'd.GetChars (socketData.dataBuffer..') каким-то образом испортила буфер, и поэтому я получил испорченные данные. Мне все еще нужно было использовать GetChars, чтобы читать первую часть пакета как строка, так что я просто изменил:
int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
чтобы:
byte[] tmp_a = new byte[socketData.dataBuffer.Length];
tmp_a = socketData.dataBuffer;
int charLen = d.GetChars(tmp_a, 0, iRx, chars, 0);
И теперь все работает гладко. Видимо, каким-то образом вызов getChars непосредственно в буфере повлиял на буфер.
1 ответ
Похоже, проблема кодирования.
Ключевой концепцией здесь является то, что кодировка предназначена для текста, а изображения не являются текстом.
Не пытайтесь кодировать или декодировать байты перед отправкой или после получения.
Точно так же, если вы читаете или записываете изображение из или в файл, не пытайтесь кодировать или декодировать, используйте двоичный режим.
Только не пытайтесь конвертировать байты в символы, нет никакого осмысленного способа сделать это.